diff --git a/.cirrus.yml b/.cirrus.yml index 907d10eb4e..97fb0f1f6a 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -13,5 +13,4 @@ freebsd_12_task: - make -j${NPROC} - src/vim --version test_script: - # Runtime Indent tests do not work, run only the normal test suite - - cd src && make test + - make test diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index f78a84b567..8fa535d540 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -8,7 +8,7 @@ labels: enhancement _Instructions: Replace the template text and remove irrelevant text (including this line)_ -**Is your feature request related something that is currently hard to do? Please describe.** +**Is your feature request about something that is currently impossible or hard to do? Please describe the problem.** A clear and concise description of what is hard to do. Ex. It is difficult to [...] when [...] (If it is related to runtime files, please check their header for where to discuss enhancements.) diff --git a/.gitignore b/.gitignore index 2fe245daa0..7474a8f2ce 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ src/xxd/xxd src/auto/if_perl.c src/auto/gui_gtk_gresources.c src/auto/gui_gtk_gresources.h +src/auto/os_haiku.rdef src/objects/.dirstamp src/objects src/tags diff --git a/Filelist b/Filelist index 422a0d0bad..422f18dd28 100644 --- a/Filelist +++ b/Filelist @@ -13,6 +13,7 @@ SRC_ALL = \ ci/appveyor.bat \ ci/if_ver*.vim \ ci/load-snd-dummy.sh \ + ci/config.mk*.sed \ src/Make_all.mak \ src/README.md \ src/alloc.h \ @@ -128,6 +129,8 @@ SRC_ALL = \ src/term.h \ src/termlib.c \ src/testing.c \ + src/textformat.c \ + src/textobject.c \ src/textprop.c \ src/time.c \ src/ui.c \ @@ -162,12 +165,12 @@ SRC_ALL = \ src/testdir/setup.vim \ src/testdir/setup_gui.vim \ src/testdir/shared.vim \ + src/testdir/vim9.vim \ src/testdir/summarize.vim \ src/testdir/term_util.vim \ src/testdir/view_util.vim \ src/testdir/test[0-9]*.ok \ src/testdir/test[0-9]*a.ok \ - src/testdir/test_[a-z]*.ok \ src/testdir/test49.vim \ src/testdir/test83-tags? \ src/testdir/test77a.com \ @@ -182,8 +185,6 @@ SRC_ALL = \ src/testdir/python_after/*.py \ src/testdir/python_before/*.py \ src/testdir/pyxfile/*.py \ - src/testdir/bench*.in \ - src/testdir/bench*.vim \ src/testdir/dumps/*.dump \ src/testdir/samples/*.txt \ src/testdir/samples/test000 \ @@ -280,6 +281,8 @@ SRC_ALL = \ src/proto/terminal.pro \ src/proto/termlib.pro \ src/proto/testing.pro \ + src/proto/textformat.pro \ + src/proto/textobject.pro \ src/proto/textprop.pro \ src/proto/time.pro \ src/proto/ui.pro \ @@ -298,10 +301,12 @@ SRC_ALL = \ src/libvterm/LICENSE \ src/libvterm/Makefile \ src/libvterm/README \ + src/libvterm/CONTRIBUTING \ src/libvterm/tbl2inc_c.pl \ src/libvterm/vterm.pc.in \ src/libvterm/doc/URLs \ src/libvterm/doc/seqs.txt \ + src/libvterm/find-wide-chars.pl \ src/libvterm/include/vterm.h \ src/libvterm/include/vterm_keycodes.h \ src/libvterm/src/encoding.c \ @@ -309,6 +314,7 @@ SRC_ALL = \ src/libvterm/src/encoding/DECdrawing.tbl \ src/libvterm/src/encoding/uk.inc \ src/libvterm/src/encoding/uk.tbl \ + src/libvterm/src/fullwidth.inc \ src/libvterm/src/keyboard.c \ src/libvterm/src/mouse.c \ src/libvterm/src/parser.c \ @@ -339,16 +345,17 @@ SRC_ALL = \ src/libvterm/t/27state_reset.test \ src/libvterm/t/28state_dbl_wh.test \ src/libvterm/t/29state_fallback.test \ - src/libvterm/t/30pen.test \ - src/libvterm/t/40screen_ascii.test \ - src/libvterm/t/41screen_unicode.test \ - src/libvterm/t/42screen_damage.test \ - src/libvterm/t/43screen_resize.test \ - src/libvterm/t/44screen_pen.test \ - src/libvterm/t/45screen_protect.test \ - src/libvterm/t/46screen_extent.test \ - src/libvterm/t/47screen_dbl_wh.test \ - src/libvterm/t/48screen_termprops.test \ + src/libvterm/t/30state_pen.test \ + src/libvterm/t/31state_rep.test \ + src/libvterm/t/60screen_ascii.test \ + src/libvterm/t/61screen_unicode.test \ + src/libvterm/t/62screen_damage.test \ + src/libvterm/t/63screen_resize.test \ + src/libvterm/t/64screen_pen.test \ + src/libvterm/t/65screen_protect.test \ + src/libvterm/t/66screen_extent.test \ + src/libvterm/t/67screen_dbl_wh.test \ + src/libvterm/t/68screen_termprops.test \ src/libvterm/t/90vttest_01-movement-1.test \ src/libvterm/t/90vttest_01-movement-2.test \ src/libvterm/t/90vttest_01-movement-3.test \ @@ -607,8 +614,9 @@ SRC_AMI = \ # source files for Haiku (also in the extra archive) SRC_HAIKU = \ + README_haiku.txt \ src/os_haiku.h \ - src/os_haiku.rdef \ + src/os_haiku.rdef.in \ src/gui_haiku.cc \ src/gui_haiku.h \ src/proto/gui_haiku.pro \ diff --git a/READMEdir/README_haiku.txt b/READMEdir/README_haiku.txt new file mode 100644 index 0000000000..860b40b0d7 --- /dev/null +++ b/READMEdir/README_haiku.txt @@ -0,0 +1,13 @@ +README_haiku.txt for version 8.2 of Vim: Vi IMproved. + +This file explains the installation of Vim on Haiku operating system. +See "README.txt" for general information about Vim. + +Preferred (and easy) way to get Vim on Haiku is to use default Haiku +software repository HaikuPorts. To get Vim: + +- Open HaikuDepot application and search for "vim" package, then install, +- Open a Terminal and type "pkgman install vim", then follow instructions. + +If you prefer to install Vim from source, follow the instructions on +"runtime/doc/os_haiku.txt", "Compiling Vim" section. diff --git a/ci/config.mk.clang.sed b/ci/config.mk.clang.sed index 40c6705ac3..da6044d830 100644 --- a/ci/config.mk.clang.sed +++ b/ci/config.mk.clang.sed @@ -1 +1,2 @@ -/^RUBY_CFLAGS\b/s/$/ -Wno-error=unknown-attributes -Wno-error=ignored-attributes/ +/^CFLAGS[[:blank:]]*=/s/$/ -Wno-error=missing-field-initializers/ +/^RUBY_CFLAGS[[:blank:]]*=/s/$/ -Wno-error=unknown-attributes -Wno-error=ignored-attributes/ diff --git a/ci/config.mk.gcc.sed b/ci/config.mk.gcc.sed index 3b11569eb0..f46e488488 100644 --- a/ci/config.mk.gcc.sed +++ b/ci/config.mk.gcc.sed @@ -1 +1 @@ -/^CFLAGS\b/s/$/ -Wno-error=maybe-uninitialized/ +/^CFLAGS[[:blank:]]*=/s/$/ -Wno-error=maybe-uninitialized/ diff --git a/ci/config.mk.sed b/ci/config.mk.sed index 31682787eb..cd2cd9c452 100644 --- a/ci/config.mk.sed +++ b/ci/config.mk.sed @@ -1,2 +1,2 @@ -/^CFLAGS\b/s/$/ -Wall -Wextra -Wshadow -Werror/ -/^PERL_CFLAGS\b/s/$/ -Wno-error=unused-function/ +/^CFLAGS[[:blank:]]*=/s/$/ -Wall -Wextra -Wshadow -Werror/ +/^PERL_CFLAGS[[:blank:]]*=/s/$/ -Wno-error=unused-function/ diff --git a/runtime/compiler/eslint.vim b/runtime/compiler/eslint.vim new file mode 100644 index 0000000000..1e7af2b182 --- /dev/null +++ b/runtime/compiler/eslint.vim @@ -0,0 +1,16 @@ +" Vim compiler file +" Compiler: ESLint for JavaScript +" Maintainer: Romain Lafourcade +" Last Change: 2020 May 17 + +if exists("current_compiler") + finish +endif +let current_compiler = "eslint" + +if exists(":CompilerSet") != 2 + command -nargs=* CompilerSet setlocal +endif + +CompilerSet makeprg=eslint\ --format\ compact +CompilerSet errorformat=%f:\ line\ %l\\,\ col\ %c\\,\ %m,%-G%.%# diff --git a/runtime/compiler/standard.vim b/runtime/compiler/standard.vim new file mode 100644 index 0000000000..b6bcf1f6b0 --- /dev/null +++ b/runtime/compiler/standard.vim @@ -0,0 +1,16 @@ +" Vim compiler file +" Compiler: Standard for JavaScript +" Maintainer: Romain Lafourcade +" Last Change: 2020 May 17 + +if exists("current_compiler") + finish +endif +let current_compiler = "standard" + +if exists(":CompilerSet") != 2 + command -nargs=* CompilerSet setlocal +endif + +CompilerSet makeprg=standard +CompilerSet errorformat=%f:\ line\ %l\\,\ col\ %c\\,\ %m,%-G%.%# diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt index 0b2c5be1db..ad297c5b11 100644 --- a/runtime/doc/change.txt +++ b/runtime/doc/change.txt @@ -1,4 +1,4 @@ -*change.txt* For Vim version 8.2. Last change: 2020 Feb 09 +*change.txt* For Vim version 8.2. Last change: 2020 Apr 26 VIM REFERENCE MANUAL by Bram Moolenaar @@ -209,7 +209,7 @@ gR Enter Virtual Replace mode: Each character you type start insert (for {Visual} see |Visual-mode|). *v_r* -{Visual}["x]r{char} Replace all selected characters by {char}. +{Visual}r{char} Replace all selected characters by {char}. *v_C* {Visual}["x]C Delete the highlighted lines [into register x] and @@ -996,9 +996,9 @@ inside of strings can change! Also see 'softtabstop' option. > 5. Copying and moving text *copy-move* *quote* -"{a-zA-Z0-9.%#:-"} Use register {a-zA-Z0-9.%#:-"} for next delete, yank - or put (use uppercase character to append with - delete and yank) ({.%#:} only work with put). +"{register} Use {register} for next delete, yank or put. Use + an uppercase character to append with delete and yank. + Registers ".", "%", "#" and ":" only work with put. *:reg* *:registers* :reg[isters] Display the type and contents of all numbered and diff --git a/runtime/doc/cmdline.txt b/runtime/doc/cmdline.txt index a01d4b97f1..ecaa73e894 100644 --- a/runtime/doc/cmdline.txt +++ b/runtime/doc/cmdline.txt @@ -1,4 +1,4 @@ -*cmdline.txt* For Vim version 8.2. Last change: 2020 Feb 29 +*cmdline.txt* For Vim version 8.2. Last change: 2020 Apr 23 VIM REFERENCE MANUAL by Bram Moolenaar @@ -615,6 +615,7 @@ followed by another Vim command: :tcl :tcldo :tclfile + :terminal :vglobal :windo :write ! diff --git a/runtime/doc/develop.txt b/runtime/doc/develop.txt index c1e5a11f29..7ed251a6f6 100644 --- a/runtime/doc/develop.txt +++ b/runtime/doc/develop.txt @@ -1,4 +1,4 @@ -*develop.txt* For Vim version 8.2. Last change: 2019 Nov 22 +*develop.txt* For Vim version 8.2. Last change: 2020 Apr 13 VIM REFERENCE MANUAL by Bram Moolenaar @@ -151,7 +151,8 @@ VIM IS... NOT *design-not* A satirical way to say this: "Unlike Emacs, Vim does not attempt to include everything but the kitchen sink, but some people say that you can clean one with it. ;-)" - To use Vim with gdb see: http://www.agide.org and http://clewn.sf.net. + To use Vim with gdb see |terminal-debugger|. Other (older) tools can be + found at http://www.agide.org and http://clewn.sf.net. - Vim is not a fancy GUI editor that tries to look nice at the cost of being less consistent over all platforms. But functional GUI features are welcomed. diff --git a/runtime/doc/editing.txt b/runtime/doc/editing.txt index 96bcb9340d..f6e3810d88 100644 --- a/runtime/doc/editing.txt +++ b/runtime/doc/editing.txt @@ -1,4 +1,4 @@ -*editing.txt* For Vim version 8.2. Last change: 2019 Dec 22 +*editing.txt* For Vim version 8.2. Last change: 2020 May 12 VIM REFERENCE MANUAL by Bram Moolenaar @@ -475,6 +475,9 @@ This edits the same file again with 'fileformat' set to "unix". > :w ++enc=latin1 newfile This writes the current buffer to "newfile" in latin1 format. +The message given when writing a file will show "[converted]" when +'fileencoding' or the value specified with ++enc differs from 'encoding'. + There may be several ++opt arguments, separated by white space. They must all appear before any |+cmd| argument. @@ -1079,9 +1082,9 @@ The names can be in upper- or lowercase. *:q* *:quit* :q[uit] Quit the current window. Quit Vim if this is the last - window. This fails when changes have been made and - Vim refuses to |abandon| the current buffer, and when - the last file in the argument list has not been + |edit-window|. This fails when changes have been made + and Vim refuses to |abandon| the current buffer, and + when the last file in the argument list has not been edited. If there are other tab pages and quitting the last window in the current tab page the current tab page is @@ -1107,18 +1110,22 @@ The names can be in upper- or lowercase. |quickfix|). *:wq* -:wq [++opt] Write the current file and quit. Writing fails when - the file is read-only or the buffer does not have a - name. Quitting fails when the last file in the - argument list has not been edited. +:wq [++opt] Write the current file and close the window. If this + was the last |edit-window| Vim quits. + Writing fails when the file is read-only or the buffer + does not have a name. Quitting fails when the last + file in the argument list has not been edited. -:wq! [++opt] Write the current file and quit. Writing fails when - the current buffer does not have a name. +:wq! [++opt] Write the current file and close the window. If this + was the last |edit-window| Vim quits. Writing fails + when the current buffer does not have a name. -:wq [++opt] {file} Write to {file} and quit. Quitting fails when the +:wq [++opt] {file} Write to {file} and close the window. If this was the + last |edit-window| Vim quits. Quitting fails when the last file in the argument list has not been edited. -:wq! [++opt] {file} Write to {file} and quit. +:wq! [++opt] {file} Write to {file} and close the current window. Quit + Vim if this was the last |edit-window|. :[range]wq[!] [++opt] [file] Same as above, but only write the lines in [range]. @@ -1135,10 +1142,10 @@ The names can be in upper- or lowercase. Same as :xit. *ZZ* -ZZ Write current file, if modified, and quit (same as - ":x"). (Note: If there are several windows for the - current file, the file is written if it was modified - and the window is closed). +ZZ Write current file, if modified, and close the current + window (same as ":x"). + If there are several windows for the current file, + only the current window is closed. *ZQ* ZQ Quit without checking for changes (same as ":q!"). diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index c063c6027b..de3246fc9c 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -1,4 +1,4 @@ -*eval.txt* For Vim version 8.2. Last change: 2020 Apr 13 +*eval.txt* For Vim version 8.2. Last change: 2020 May 25 VIM REFERENCE MANUAL by Bram Moolenaar @@ -584,6 +584,8 @@ adict. Weeding out entries from a Dictionary can be done with |filter()|: > :call filter(dict, 'v:val =~ "x"') This removes all entries from "dict" with a value not matching 'x'. +This can also be used to remove all entries: > + call filter(dict, 0) Dictionary function ~ @@ -1485,7 +1487,7 @@ the function returns: > :echo Bar(6) < 5 -Note that the variables must exist in the outer scope before the lamba is +Note that the variables must exist in the outer scope before the lambda is defined for this to work. See also |:func-closure|. Lambda and closure support can be checked with: > @@ -1809,10 +1811,12 @@ v:errors Errors found by assert functions, such as |assert_true()|. v:event Dictionary containing information about the current |autocommand|. See the specific event for what it puts in this dictionary. - The dictionary is emptied when the |autocommand| - finishes, please refer to |dict-identity| for how to get an - independent copy of it. - + The dictionary is emptied when the |autocommand| finishes, + please refer to |dict-identity| for how to get an independent + copy of it. Use |deepcopy()| if you want to keep the + information after the event triggers. Example: > + au TextYankPost * let g:foo = deepcopy(v:event) +< *v:exception* *exception-variable* v:exception The value of the exception most recently caught and not finished. See also |v:throwpoint| and |throw-variables|. @@ -2596,6 +2600,8 @@ maparg({name} [, {mode} [, {abbr} [, {dict}]]]) rhs of mapping {name} in mode {mode} mapcheck({name} [, {mode} [, {abbr}]]) String check for mappings matching {name} +mapset({mode}, {abbr}, {dict}) + none restore mapping from |maparg()| result match({expr}, {pat} [, {start} [, {count}]]) Number position where {pat} matches in {expr} matchadd({group}, {pattern} [, {priority} [, {id} [, {dict}]]]) @@ -2637,6 +2643,8 @@ popup_findpreview() Number get window ID of preview popup window popup_getoptions({id}) Dict get options of popup window {id} popup_getpos({id}) Dict get position of popup window {id} popup_hide({id}) none hide popup menu {id} +popup_list() List get a list of window IDs of al popups +popup_locate({row}, {col}) Number get window ID of popup at position popup_menu({what}, {options}) Number create a popup window used as a menu popup_move({id}, {options}) none set position of popup window {id} popup_notification({what}, {options}) @@ -2656,7 +2664,7 @@ prop_clear({lnum} [, {lnum-end} [, {props}]]) none remove all text properties prop_find({props} [, {direction}]) Dict search for a text property -prop_list({lnum} [, {props}) List text properties in {lnum} +prop_list({lnum} [, {props}]) List text properties in {lnum} prop_remove({props} [, {lnum} [, {lnum-end}]]) Number remove a text property prop_type_add({name}, {props}) none define a new property type @@ -2664,7 +2672,7 @@ prop_type_change({name}, {props}) none change an existing property type prop_type_delete({name} [, {props}]) none delete a property type -prop_type_get([{name} [, {props}]) +prop_type_get([{name} [, {props}]]) Dict get property type values prop_type_list([{props}]) List get list of property types pum_getpos() Dict position and size of pum if visible @@ -2913,15 +2921,16 @@ win_execute({id}, {command} [, {silent}]) String execute {command} in window {id} win_findbuf({bufnr}) List find windows containing {bufnr} win_getid([{win} [, {tab}]]) Number get window ID for {win} in {tab} +win_gettype([{nr}]) String type of window {nr} win_gotoid({expr}) Number go to window with ID {expr} win_id2tabwin({expr}) List get tab and window nr from window ID win_id2win({expr}) Number get window nr from window ID win_screenpos({nr}) List get screen position of window {nr} win_splitmove({nr}, {target} [, {options}]) Number move window {nr} to split of {target} -win_type([{nr}]) String type of window {nr} winbufnr({nr}) Number buffer number of window {nr} wincol() Number window column of the cursor +windowsversion() String MS-Windows OS version winheight({nr}) Number height of window {nr} winlayout([{tabnr}]) List layout of windows in tab {tabnr} winline() Number window line of the cursor @@ -3060,7 +3069,7 @@ arglistid([{winnr} [, {tabnr}]]) {winnr} can be the window number or the |window-ID|. *argv()* -argv([{nr} [, {winid}]) +argv([{nr} [, {winid}]]) The result is the {nr}th file in the argument list. See |arglist|. "argv(0)" is the first one. Example: > :let i = 0 @@ -5864,7 +5873,7 @@ has({feature} [, {check}]) Note that to skip code that has a syntax error when the feature is not available, Vim may skip the rest of the line - and miss a following `endif`. Therfore put the `endif` on a + and miss a following `endif`. Therefore put the `endif` on a separate line: > if has('feature') let x = this->breaks->without->the->feature @@ -6802,6 +6811,7 @@ map({expr1}, {expr2}) *map()* Can also be used as a |method|: > mylist->map(expr2) + maparg({name} [, {mode} [, {abbr} [, {dict}]]]) *maparg()* When {dict} is omitted or zero: Return the rhs of mapping {name} in mode {mode}. The returned String has special @@ -6834,7 +6844,10 @@ maparg({name} [, {mode} [, {abbr} [, {dict}]]]) *maparg()* When {dict} is there and it is |TRUE| return a dictionary containing all the information of the mapping with the following items: - "lhs" The {lhs} of the mapping. + "lhs" The {lhs} of the mapping as it would be typed + "lhsraw" The {lhs} of the mapping as raw bytes + "lhsrawalt" The {lhs} of the mapping as raw bytes, alternate + form, only present when it differs from "lhsraw" "rhs" The {rhs} of the mapping as typed. "silent" 1 for a |:map-silent| mapping, else 0. "noremap" 1 if the {rhs} of the mapping is not remappable. @@ -6853,6 +6866,9 @@ maparg({name} [, {mode} [, {abbr} [, {dict}]]]) *maparg()* "nowait" Do not wait for other, longer mappings. (|:map-|). + The dictionary can be used to restore a mapping with + |mapset()|. + The mappings local to the current buffer are checked first, then the global mappings. This function can be used to map a key even when it's already @@ -6898,6 +6914,23 @@ mapcheck({name} [, {mode} [, {abbr}]]) *mapcheck()* Can also be used as a |method|: > GetKey()->mapcheck('n') + +mapset({mode}, {abbr}, {dict}) *mapset()* + Restore a mapping from a dictionary returned by |maparg()|. + {mode} and {abbr} should be the same as for the call to + |maparg()|. *E460* + {mode} is used to define the mode in which the mapping is set, + not the "mode" entry in {dict}. + Example for saving and restoring a mapping: > + let save_map = maparg('K', 'n', 0, 1) + nnoremap K somethingelse + ... + call mapset('n', 0, save_map) +< Note that if you are going to replace a map in several modes, + e.g. with `:map!`, you need to save the mapping for all of + them, since they can differe. + + match({expr}, {pat} [, {start} [, {count}]]) *match()* When {expr} is a |List| then this returns the index of the first item where {pat} matches. Each item is used as a @@ -7778,7 +7811,7 @@ range({expr} [, {max} [, {stride}]]) *range()* GetExpr()->range() < -rand([{expr}]) *rand()* +rand([{expr}]) *rand()* *random* Return a pseudo-random Number generated with an xoshiro128** algorithm using seed {expr}. The returned number is 32 bits, also on 64 bits systems, for consistency. @@ -8651,8 +8684,8 @@ setloclist({nr}, {list} [, {action} [, {what}]]) *setloclist()* GetLoclist()->setloclist(winnr) setmatches({list} [, {win}]) *setmatches()* - Restores a list of matches saved by |getmatches() for the - current window|. Returns 0 if successful, otherwise -1. All + Restores a list of matches saved by |getmatches()| for the + current window. Returns 0 if successful, otherwise -1. All current matches are cleared before the list is restored. See example for |getmatches()|. If {win} is specified, use the window with this number or @@ -10203,7 +10236,7 @@ tr({src}, {fromstr}, {tostr}) *tr()* trim({text} [, {mask}]) *trim()* Return {text} as a String where any character in {mask} is - removed from the beginning and end of {text}. + removed from the beginning and end of {text}. If {mask} is not given, {mask} is all characters up to 0x20, which includes Tab, space, NL and CR, plus the non-breaking space character 0xa0. @@ -11131,6 +11164,8 @@ See |:verbose-cmd| for more information. NOTE: Use ! wisely. If used without care it can cause an existing function to be replaced unexpectedly, which is hard to debug. + NOTE: In Vim9 script script-local functions cannot be + deleted or redefined. For the {arguments} see |function-argument|. diff --git a/runtime/doc/help.txt b/runtime/doc/help.txt index 409e116494..6873338d24 100644 --- a/runtime/doc/help.txt +++ b/runtime/doc/help.txt @@ -199,13 +199,13 @@ Remarks about specific systems ~ |os_amiga.txt| Amiga |os_beos.txt| BeOS and BeBox |os_dos.txt| MS-DOS and MS-Windows common items +|os_haiku.txt| Haiku |os_mac.txt| Macintosh |os_mint.txt| Atari MiNT |os_msdos.txt| MS-DOS (plain DOS and DOS box under Windows) |os_os2.txt| OS/2 |os_qnx.txt| QNX |os_risc.txt| RISC-OS -|os_haiku.txt| Haiku |os_unix.txt| Unix |os_vms.txt| VMS |os_win32.txt| MS-Windows diff --git a/runtime/doc/if_lua.txt b/runtime/doc/if_lua.txt index 75bb963a9f..63e227d303 100644 --- a/runtime/doc/if_lua.txt +++ b/runtime/doc/if_lua.txt @@ -1,4 +1,4 @@ -*if_lua.txt* For Vim version 8.2. Last change: 2019 Jul 21 +*if_lua.txt* For Vim version 8.2. Last change: 2020 May 17 VIM REFERENCE MANUAL by Luis Carvalho @@ -199,6 +199,15 @@ Vim evaluation and command execution, and others. returns it. Note that the buffer is not set as current. + vim.call({name} [,{args}]) + Proxy to call Vim function named {name} with + arguments {args}. Example: > + :lua print(vim.call('has', 'timers')) +< + vim.fn Proxy to call Vim functions. Proxy methods are + created on demand. Example: > + :lua print(vim.fn.has('timers')) +< ============================================================================== 3. List userdata *lua-list* diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt index c2a04f2554..d3ae57ef68 100644 --- a/runtime/doc/index.txt +++ b/runtime/doc/index.txt @@ -1,4 +1,4 @@ -*index.txt* For Vim version 8.2. Last change: 2020 Mar 27 +*index.txt* For Vim version 8.2. Last change: 2020 May 26 VIM REFERENCE MANUAL by Bram Moolenaar @@ -246,8 +246,7 @@ tag char note action in Normal mode ~ 2 filter Nmove text through the {filter} command |!!| !!{filter} 2 filter N lines through the {filter} command -|quote| "{a-zA-Z0-9.%#:-"} use register {a-zA-Z0-9.%#:-"} for next - delete, yank or put (uppercase to append) +|quote| "{register} use {register} for next delete, yank or put ({.%#:} only work with put) |#| # 1 search backward for the Nth occurrence of the ident under the cursor @@ -365,8 +364,8 @@ tag char note action in Normal mode ~ register x] |Y| ["x]Y yank N lines [into register x]; synonym for "yy" -|ZZ| ZZ store current file if modified, and exit -|ZQ| ZQ exit current file always +|ZZ| ZZ write if buffer changed and close window +|ZQ| ZQ close window without writing |[| [{char} square bracket command (see |[| below) \ not used |]| ]{char} square bracket command (see |]| below) @@ -829,7 +828,7 @@ tag char note action in Normal mode ~ |zD| zD delete folds recursively |zE| zE eliminate all folds |zF| zF create a fold for N lines -|zG| zG mark word as good spelled word +|zG| zG temporarily mark word as good spelled word |zH| zH when 'wrap' off scroll half a screenwidth to the right |zL| zL when 'wrap' off scroll half a screenwidth @@ -838,7 +837,7 @@ tag char note action in Normal mode ~ |zN| zN set 'foldenable' |zO| zO open folds recursively |zR| zR set 'foldlevel' to the deepest fold -|zW| zW mark word as wrong (bad) spelled word +|zW| zW temporarily mark word as bad spelled word |zX| zX re-apply 'foldlevel' |z^| z^ cursor on line N (default line above window), otherwise like "z-" @@ -850,7 +849,7 @@ tag char note action in Normal mode ~ position the cursor at the end (right side) of the screen |zf| zf{motion} create a fold for Nmove text -|zg| zg mark word as good spelled word +|zg| zg permanently mark word as good spelled word |zh| zh when 'wrap' off scroll screen N characters to the right |zi| zi toggle 'foldenable' @@ -871,7 +870,7 @@ tag char note action in Normal mode ~ |zuW| zuW undo |zW| |zuG| zuG undo |zG| |zv| zv open enough folds to view the cursor line -|zw| zw mark word as wrong (bad) spelled word +|zw| zw permanently mark word as bad spelled word |zx| zx re-apply 'foldlevel' and do "zv" |zz| zz redraw, cursor line at center of window |z| z same as "zh" @@ -1115,7 +1114,7 @@ tag char action in Terminal-Job mode ~ |t_CTRL-W_:| CTRL-W : enter an Ex command |t_CTRL-W_.| CTRL-W . type CTRL-W in the terminal CTRL-W CTRL-\ send a CTRL-\ to the job in the terminal -|t_CTRL-W_quote| CTRL-W " {0-9a-z"%#*:=} +|t_CTRL-W_quote| CTRL-W " {register} paste register in the terminal |t_CTRL-W_CTRL-C| CTRL-W CTRL-C forcefully ends the job |t_CTRL-W_CTRL-W| CTRL-W CTRL-W move focus to the next window @@ -1263,6 +1262,7 @@ tag command action ~ |:debug| :deb[ug] run a command in debugging mode |:debuggreedy| :debugg[reedy] read debug mode commands from normal input |:def| :def define a Vim9 user function +|:defcompile| :defc[ompile] compile Vim9 user functions in current script |:delcommand| :delc[ommand] delete user-defined command |:delfunction| :delf[unction] delete a user function |:delmarks| :delm[arks] delete marks @@ -1724,7 +1724,7 @@ tag command action ~ |:wqall| :wqa[ll] write all changed buffers and quit Vim |:wundo| :wu[ndo] write undo information to a file |:wviminfo| :wv[iminfo] write to viminfo file -|:xit| :x[it] write if buffer changed and quit window or Vim +|:xit| :x[it] write if buffer changed and close window |:xall| :xa[ll] same as ":wqall" |:xmapclear| :xmapc[lear] remove all mappings for Visual mode |:xmap| :xm[ap] like ":map" but for Visual mode diff --git a/runtime/doc/insert.txt b/runtime/doc/insert.txt index 99c2d40e7d..fed81e5db4 100644 --- a/runtime/doc/insert.txt +++ b/runtime/doc/insert.txt @@ -1,4 +1,4 @@ -*insert.txt* For Vim version 8.2. Last change: 2020 Mar 25 +*insert.txt* For Vim version 8.2. Last change: 2020 Apr 30 VIM REFERENCE MANUAL by Bram Moolenaar @@ -666,8 +666,10 @@ Note: The keys that are valid in CTRL-X mode are not mapped. This allows for ends CTRL-X mode (any key that is not a valid CTRL-X mode command) is mapped. Also, when doing completion with 'complete' mappings apply as usual. -Note: While completion is active Insert mode can't be used recursively. -Mappings that somehow invoke ":normal i.." will generate an E523 error. + *E578* *E565* +Note: While completion is active Insert mode can't be used recursively and +buffer text cannot be changed. Mappings that somehow invoke ":normal i.." +will generate an E565 error. The following mappings are suggested to make typing the completion commands a bit easier (although they will hide other commands): > diff --git a/runtime/doc/makehtml.awk b/runtime/doc/makehtml.awk index 5e40069391..40154b063b 100644 --- a/runtime/doc/makehtml.awk +++ b/runtime/doc/makehtml.awk @@ -58,7 +58,7 @@ substr($0,length($0),1) == "~" { print "" substr($0,1, # #ad hoc code # -/^"\|\& / {gsub(/\|/,"\\|"); } +/^"\|& / {gsub(/\|/,"\\|"); } / = b / {gsub(/ b /," \\b "); } # # one letter tag diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt index bf643c0ffc..c142f231b5 100644 --- a/runtime/doc/map.txt +++ b/runtime/doc/map.txt @@ -1,4 +1,4 @@ -*map.txt* For Vim version 8.2. Last change: 2019 Dec 19 +*map.txt* For Vim version 8.2. Last change: 2020 Apr 23 VIM REFERENCE MANUAL by Bram Moolenaar @@ -1492,7 +1492,7 @@ The valid escape sequences are (See the '-bang' attribute) Expands to a ! if the command was executed with a ! modifier, otherwise expands to nothing. - ** + ** *:command-modifiers* The command modifiers, if specified. Otherwise, expands to nothing. Supported modifiers are |:aboveleft|, |:belowright|, |:botright|, |:browse|, |:confirm|, |:hide|, |:keepalt|, diff --git a/runtime/doc/netbeans.txt b/runtime/doc/netbeans.txt index ac85623670..803d388f4d 100644 --- a/runtime/doc/netbeans.txt +++ b/runtime/doc/netbeans.txt @@ -1,4 +1,4 @@ -*netbeans.txt* For Vim version 8.2. Last change: 2019 May 05 +*netbeans.txt* For Vim version 8.2. Last change: 2020 Apr 19 VIM REFERENCE MANUAL by Gordon Prieur et al. diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 905dbdf528..3d4546727e 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1,4 +1,4 @@ -*options.txt* For Vim version 8.2. Last change: 2020 Apr 10 +*options.txt* For Vim version 8.2. Last change: 2020 May 03 VIM REFERENCE MANUAL by Bram Moolenaar @@ -8484,9 +8484,11 @@ A jump table for the options with a short description can be found at |Q_op|. Currently, these messages are given: >= 1 When the viminfo file is read or written. >= 2 When a file is ":source"'ed. + >= 4 Shell commands. >= 5 Every searched tags file and include file. >= 8 Files for which a group of autocommands is executed. >= 9 Every executed autocommand. + >= 11 Finding items in a path >= 12 Every executed function. >= 13 When an exception is thrown, caught, finished, or discarded. >= 14 Anything pending in a ":finally" clause. diff --git a/runtime/doc/os_haiku.txt b/runtime/doc/os_haiku.txt index 2c02994d50..5c520b0683 100644 --- a/runtime/doc/os_haiku.txt +++ b/runtime/doc/os_haiku.txt @@ -1,4 +1,4 @@ -*os_haiku.txt* For Vim version 8.2. Last change: 2020 Mar 19 +*os_haiku.txt* For Vim version 8.2. Last change: 2020 May 13 VIM REFERENCE MANUAL by Bram Moolenaar @@ -25,8 +25,9 @@ targets personal computing. 9. The meta key modifier |haiku-meta| 10. Mouse key mappings |haiku-mouse| 11. Color names |haiku-colors| -12. Credits |haiku-support-credits| -13. Bugs & to-do |haiku-bugs| +12. GUI Toolbar Images |haiku-toolbar-images| +13. Credits |haiku-support-credits| +14. Bugs & to-do |haiku-bugs| 1. General *haiku-general* @@ -46,12 +47,11 @@ features you can enable/disable. Haiku uses "ncurses6" as its terminal library, therefore you need to have "ncurses6_devel" package installed from HaikuDepot in order to configure -the Haiku build. Just append "--with-tlib=ncurses6" to ./configure command -below for the initial build. +the Haiku build. Just append "--with-tlib=ncurses6" to ./configure command Now you should use "make" to compile Vim, then "make install" to install it. For seamless integration into Haiku, the GUI-less vim binary should be -additionally installed over the GUI version. Typical build commands are: > +additionally installed over the GUI version. Typical build commands are: ./configure --prefix=`finddir B_SYSTEM_NONPACKAGED_DIRECTORY` \ --datarootdir=`finddir B_SYSTEM_NONPACKAGED_DATA_DIRECTORY` \ @@ -71,25 +71,25 @@ additionally installed over the GUI version. Typical build commands are: > Normally Vim starts with the GUI if you start it as gvim or vim -g. The vim version with GUI tries to determine if it was started from the Tracker instead -of the Terminal, and if so, uses the GUI anyway. However, the current detection +of the Terminal, and if so, uses the GUI anyway. However, the current detection scheme is fooled if you use the command "vim - +The default value for $VIM is set at compile time and can be determined with: :version @@ -117,7 +117,7 @@ The normal value is /boot/home/config/settings. You can drop files and directories on either the Vim icon (starts a new Vim session, unless you use the File Types application to set Vim to be "Single Launch") or on the Vim window (starts editing the files). Dropping a folder -sets Vim's current working directory. |:cd| |:pwd| If you drop files or +sets Vim's current working directory |:cd| |:pwd|. If you drop files or folders with either SHIFT key pressed, Vim changes directory to the folder that contains the first item dropped. When starting Vim, there is no need to press shift: Vim behaves as if you do. @@ -164,7 +164,7 @@ isn't a dotted-y, then for this font the encoding does not work. If the font you specify is unavailable, you get the system fixed font. -GUI Font Selection Dialog is available at giving the > +GUI Font Selection Dialog is available at giving the: :set guifont=* @@ -221,7 +221,7 @@ All the changes and patches released under vim-license. Thank you, all! -13. Bugs & to-do *haiku-bugs* +14. Bugs & to-do *haiku-bugs* The port is under development now and far away from the perfect state. For bug reports, patches and wishes, please use the Vim mailing list or Vim Github diff --git a/runtime/doc/os_win32.txt b/runtime/doc/os_win32.txt index 7f378457d7..1017d4d261 100644 --- a/runtime/doc/os_win32.txt +++ b/runtime/doc/os_win32.txt @@ -230,7 +230,7 @@ A. VisionFS can't handle certain dot (.) three letter extension file names. SCO declares this behavior required for backwards compatibility with 16bit DOS/Windows environments. The two commands below demonstrate the behavior: > - echo Hello > file.bat~ + echo Hello > file.bat~ dir > file.bat < The result is that the "dir" command updates the "file.bat~" file, instead diff --git a/runtime/doc/popup.txt b/runtime/doc/popup.txt index 79aab40fe9..ff99fce9ab 100644 --- a/runtime/doc/popup.txt +++ b/runtime/doc/popup.txt @@ -1,4 +1,4 @@ -*popup.txt* For Vim version 8.2. Last change: 2020 Mar 21 +*popup.txt* For Vim version 8.2. Last change: 2020 May 18 VIM REFERENCE MANUAL by Bram Moolenaar @@ -150,6 +150,7 @@ different: *E863* - When the job ends, the popup window closes. - The popup window can be closed with `popup_close()`, the terminal buffer then becomes hidden. +- It is not possible to open a second popup window with a terminal. *E861* - The default Pmenu color is only used for the border and padding. To change the color of the terminal itself set the Terminal highlight group before creating the terminal. Setting 'wincolor' later can work but requires the @@ -197,6 +198,7 @@ Other: |popup_getoptions()| get current options for a popup |popup_getpos()| get actual position and size of a popup |popup_locate()| find popup window at a screen position + |popup_list()| get list of all popups DETAILS *popup-function-details* @@ -235,8 +237,15 @@ popup_beval({what}, {options}) *popup_beval()* GetText()->popup_beval({}) < *popup_clear()* -popup_clear() Emergency solution to a misbehaving plugin: close all popup +popup_clear([{force}]) + Emergency solution to a misbehaving plugin: close all popup windows for the current tab and global popups. + Close callbacks are not invoked. + When {force} is not present this will fail if the current + window is a popup. + When {force} is present and |TRUE| the popup is also closed + when it is the current window. If a terminal is running in a + popup it is killed. popup_close({id} [, {result}]) *popup_close()* @@ -415,6 +424,10 @@ popup_hide({id}) *popup_hide()* Can also be used as a |method|: > GetPopup()->popup_hide() +popup_list() *popup_list()* + Return a List with the |window-ID| of all existing popups. + + popup_locate({row}, {col}) *popup_locate()* Return the |window-ID| of the popup at screen position {row} and {col}. If there are multiple popups the one with the @@ -535,6 +548,8 @@ popup_setoptions({id}, {options}) *popup_setoptions()* wrap zindex The options from |popup_move()| can also be used. + Generally, setting an option to zero or an empty string resets + it to the default value, but there are exceptions. For "hidden" use |popup_hide()| and |popup_show()|. "tabpage" cannot be changed. @@ -579,15 +594,15 @@ The second argument of |popup_create()| is a dictionary with options: line Screen line where to position the popup. Can use a number or "cursor", "cursor+1" or "cursor-1" to use the line of the cursor and add or subtract a number of - lines. If omitted the popup is vertically centered. - The first line is 1. + lines. If omitted or zero the popup is vertically + centered. The first line is 1. When using "textprop" the number is relative to the text property and can be negative. col Screen column where to position the popup. Can use a number or "cursor" to use the column of the cursor, "cursor+9" or "cursor-9" to add or subtract a number - of columns. If omitted the popup is horizontally - centered. The first column is 1. + of columns. If omitted or zero the popup is + horizontally centered. The first column is 1. When using "textprop" the number is relative to the text property and can be negative. pos "topleft", "topright", "botleft" or "botright": diff --git a/runtime/doc/recover.txt b/runtime/doc/recover.txt index 0bab64a295..34f7f18451 100644 --- a/runtime/doc/recover.txt +++ b/runtime/doc/recover.txt @@ -1,4 +1,4 @@ -*recover.txt* For Vim version 8.2. Last change: 2020 Mar 24 +*recover.txt* For Vim version 8.2. Last change: 2020 May 09 VIM REFERENCE MANUAL by Bram Moolenaar @@ -125,12 +125,12 @@ If you want to make sure that your changes are in the swap file use this command: *:pre* *:preserve* *E313* *E314* -:pre[serve] Write all text for all buffers into swap files. The - original file is no longer needed for recovery. - This sets a flag in the current buffer. When the '&' - flag is present in 'cpoptions' the swap file will not - be deleted for this buffer when Vim exits and the - buffer is still loaded |cpo-&|. +:pre[serve] Write all text for the current buffer into its swap + file. The original file is no longer needed for + recovery. This sets a flag in the current buffer. + When the '&' flag is present in 'cpoptions' the swap + file will not be deleted for this buffer when Vim + exits and the buffer is still loaded |cpo-&|. A Vim swap file can be recognized by the first six characters: "b0VIM ". After that comes the version number, e.g., "3.0". diff --git a/runtime/doc/repeat.txt b/runtime/doc/repeat.txt index 04e09d3f52..29cdd73bb3 100644 --- a/runtime/doc/repeat.txt +++ b/runtime/doc/repeat.txt @@ -1,4 +1,4 @@ -*repeat.txt* For Vim version 8.2. Last change: 2019 Dec 07 +*repeat.txt* For Vim version 8.2. Last change: 2020 May 14 VIM REFERENCE MANUAL by Bram Moolenaar @@ -126,6 +126,11 @@ q{0-9a-zA-Z"} Record typed characters into register {0-9a-zA-Z"} recorded macro and the yank will overwrite the recorded macro. + Note: The recording happens while you type, replaying + the register happens as if the keys come from a + mapping. This matters, for example, for undo, which + only syncs when commands were typed. + q Stops recording. (Implementation note: The 'q' that stops recording is not stored in the register, unless it was the result of a mapping) @@ -137,7 +142,7 @@ q Stops recording. (Implementation note: The 'q' that used. The register is executed like a mapping, that means that the difference between 'wildchar' and 'wildcharm' - applies. + applies, and undo might not be synced in the same way. For "@=" you are prompted to enter an expression. The result of the expression is then executed. See also |@:|. @@ -166,7 +171,7 @@ q Stops recording. (Implementation note: The 'q' that [addr] (default is current line). :[addr]@ *:@@* -:[addr]@@ Repeat the previous :@{0-9a-z"}. First set cursor at +:[addr]@@ Repeat the previous :@{register}. First set cursor at line [addr] (default is current line). ============================================================================== diff --git a/runtime/doc/tags b/runtime/doc/tags index 7114e7df93..e1c69bd1b7 100644 --- a/runtime/doc/tags +++ b/runtime/doc/tags @@ -2295,6 +2295,7 @@ $VIM_POSIX vi_diff.txt /*$VIM_POSIX* :command-completion-custom map.txt /*:command-completion-custom* :command-completion-customlist map.txt /*:command-completion-customlist* :command-count map.txt /*:command-count* +:command-modifiers map.txt /*:command-modifiers* :command-nargs map.txt /*:command-nargs* :command-range map.txt /*:command-range* :command-register map.txt /*:command-register* @@ -2339,6 +2340,8 @@ $VIM_POSIX vi_diff.txt /*$VIM_POSIX* :debugg repeat.txt /*:debugg* :debuggreedy repeat.txt /*:debuggreedy* :def vim9.txt /*:def* +:defc vim9.txt /*:defc* +:defcompile vim9.txt /*:defcompile* :del change.txt /*:del* :delc map.txt /*:delc* :delcommand map.txt /*:delcommand* @@ -4306,6 +4309,7 @@ E457 print.txt /*E457* E458 message.txt /*E458* E459 message.txt /*E459* E46 message.txt /*E46* +E460 eval.txt /*E460* E461 eval.txt /*E461* E462 editing.txt /*E462* E463 netbeans.txt /*E463* @@ -4417,6 +4421,7 @@ E561 if_cscop.txt /*E561* E562 if_cscop.txt /*E562* E563 if_cscop.txt /*E563* E564 if_cscop.txt /*E564* +E565 insert.txt /*E565* E566 if_cscop.txt /*E566* E567 if_cscop.txt /*E567* E568 if_cscop.txt /*E568* @@ -4428,6 +4433,7 @@ E574 starting.txt /*E574* E575 starting.txt /*E575* E576 starting.txt /*E576* E577 starting.txt /*E577* +E578 insert.txt /*E578* E579 eval.txt /*E579* E580 eval.txt /*E580* E581 eval.txt /*E581* @@ -4729,6 +4735,7 @@ E855 autocmd.txt /*E855* E858 eval.txt /*E858* E859 eval.txt /*E859* E86 windows.txt /*E86* +E861 popup.txt /*E861* E862 eval.txt /*E862* E863 popup.txt /*E863* E864 pattern.txt /*E864* @@ -6209,6 +6216,7 @@ edit-files editing.txt /*edit-files* edit-intro editing.txt /*edit-intro* edit-no-break usr_25.txt /*edit-no-break* edit-paragraph-join usr_25.txt /*edit-paragraph-join* +edit-window windows.txt /*edit-window* editing.txt editing.txt /*editing.txt* efm-%> quickfix.txt /*efm-%>* efm-entries quickfix.txt /*efm-entries* @@ -7825,6 +7833,7 @@ mapmode-v map.txt /*mapmode-v* mapmode-x map.txt /*mapmode-x* mapping map.txt /*mapping* mapping-functions usr_41.txt /*mapping-functions* +mapset() eval.txt /*mapset()* mark motion.txt /*mark* mark-functions usr_41.txt /*mark-functions* mark-motions motion.txt /*mark-motions* @@ -8512,6 +8521,7 @@ popup_findpreview() popup.txt /*popup_findpreview()* popup_getoptions() popup.txt /*popup_getoptions()* popup_getpos() popup.txt /*popup_getpos()* popup_hide() popup.txt /*popup_hide()* +popup_list() popup.txt /*popup_list()* popup_locate() popup.txt /*popup_locate()* popup_menu() popup.txt /*popup_menu()* popup_menu-shortcut-example popup.txt /*popup_menu-shortcut-example* @@ -8713,6 +8723,7 @@ quote~ change.txt /*quote~* r change.txt /*r* r.vim syntax.txt /*r.vim* rand() eval.txt /*rand()* +random eval.txt /*random* range() eval.txt /*range()* raw-terminal-mode term.txt /*raw-terminal-mode* rcp pi_netrw.txt /*rcp* @@ -9588,6 +9599,7 @@ termdebug-prompt terminal.txt /*termdebug-prompt* termdebug-starting terminal.txt /*termdebug-starting* termdebug-stepping terminal.txt /*termdebug-stepping* termdebug-variables terminal.txt /*termdebug-variables* +termdebug_map_K terminal.txt /*termdebug_map_K* termdebug_popup terminal.txt /*termdebug_popup* termdebug_shortcuts terminal.txt /*termdebug_shortcuts* termdebug_use_prompt terminal.txt /*termdebug_use_prompt* @@ -10092,6 +10104,7 @@ vim-variable eval.txt /*vim-variable* vim.vim syntax.txt /*vim.vim* vim7 version7.txt /*vim7* vim8 version8.txt /*vim8* +vim9 vim9.txt /*vim9* vim9-differences vim9.txt /*vim9-differences* vim9-export vim9.txt /*vim9-export* vim9-import vim9.txt /*vim9-import* diff --git a/runtime/doc/tagsrch.txt b/runtime/doc/tagsrch.txt index 0b22deba13..bab1a1c5d7 100644 --- a/runtime/doc/tagsrch.txt +++ b/runtime/doc/tagsrch.txt @@ -1,4 +1,4 @@ -*tagsrch.txt* For Vim version 8.2. Last change: 2020 Apr 03 +*tagsrch.txt* For Vim version 8.2. Last change: 2020 Apr 19 VIM REFERENCE MANUAL by Bram Moolenaar @@ -527,10 +527,13 @@ a tag for each "#defined" macro, typedefs, enums, etc. Some programs that generate tags files: ctags As found on most Unix systems. Only supports C. Only does the basic work. +universal ctags A maintained version of ctags based on exuberant + ctags. See https://ctags.io. *Exuberant_ctags* exuberant ctags This is a very good one. It works for C, C++, Java, Fortran, Eiffel and others. It can generate tags for many items. See http://ctags.sourceforge.net. + No new version since 2009. etags Connected to Emacs. Supports many languages. JTags For Java, in Java. It can be found at http://www.fleiner.com/jtags/. diff --git a/runtime/doc/term.txt b/runtime/doc/term.txt index 4bff36565f..9e0b0bb43b 100644 --- a/runtime/doc/term.txt +++ b/runtime/doc/term.txt @@ -1,4 +1,4 @@ -*term.txt* For Vim version 8.2. Last change: 2019 Dec 07 +*term.txt* For Vim version 8.2. Last change: 2020 Apr 12 VIM REFERENCE MANUAL by Bram Moolenaar @@ -545,6 +545,7 @@ Note about colors: The 't_Co' option tells Vim the number of colors available. When it is non-zero, the 't_AB' and 't_AF' options are used to set the color. If one of these is not available, 't_Sb' and 't_Sf' are used. 't_me' is used to reset to the default colors. Also see 'termguicolors'. +When the GUI is running 't_Co' is set to 16777216. *termcap-cursor-shape* *termcap-cursor-color* When Vim enters Insert mode the 't_SI' escape sequence is sent. When Vim diff --git a/runtime/doc/terminal.txt b/runtime/doc/terminal.txt index 8105b072f4..1a3cabbad9 100644 --- a/runtime/doc/terminal.txt +++ b/runtime/doc/terminal.txt @@ -1,4 +1,4 @@ -*terminal.txt* For Vim version 8.2. Last change: 2020 Mar 26 +*terminal.txt* For Vim version 8.2. Last change: 2020 May 24 VIM REFERENCE MANUAL by Bram Moolenaar @@ -120,7 +120,7 @@ break (cursor keys start with an Esc, so they may break): > You can also create menus similar to terminal mode mappings, but you have to use |:tlmenu| instead of |:tmenu|. -< *options-in-terminal* + *options-in-terminal* After opening the terminal window and setting 'buftype' to "terminal" the TerminalOpen autocommand event is triggered. This makes it possible to set options specifically for the window and buffer. Example: > @@ -161,6 +161,7 @@ terminal windows may be configured using the variable hexadecimal color codes, similar to those accepted by |highlight-guifg|. When not using GUI colors, the terminal window always uses the 16 ANSI colors of the underlying terminal. +When using `term_start()` the colors can be set with the "ansi_colors" option. The |term_setansicolors()| function can be used to change the colors, and |term_getansicolors()| to get the currently used colors. @@ -183,6 +184,10 @@ Command syntax ~ keep the terminal open in Terminal-Normal mode. This can be changed with the ++close argument. + No Vim command can follow, any | is included in + [command]. Use `:execute` if you must have a Vim + command following in the same line. + A new buffer will be created, using [command] or 'shell' as the name, prefixed with a "!". If a buffer by this name already exists a number is added in @@ -1301,7 +1306,7 @@ breakpoint, or use the "Clear breakpoint" right-click menu entry. Inspecting variables ~ *termdebug-variables* *:Evaluate* `:Evaluate` evaluate the expression under the cursor - `K` same + `K` same (see |termdebug_map_K| to disable) `:Evaluate` {expr} evaluate {expr} `:'<,'>Evaluate` evaluate the Visually selected text @@ -1332,6 +1337,10 @@ in a buffer with 'buftype' set to "prompt". This works slightly differently: *termdebug_use_prompt* Prompt mode can be used even when the |+terminal| feature is present with: > let g:termdebug_use_prompt = 1 +< + *termdebug_map_K* +The K key is normally mapped to :Evaluate. If you do not want this use: > + let g:termdebug_map_K = 0 Communication ~ diff --git a/runtime/doc/textprop.txt b/runtime/doc/textprop.txt index 5d55952eb5..0793940b6d 100644 --- a/runtime/doc/textprop.txt +++ b/runtime/doc/textprop.txt @@ -101,7 +101,7 @@ Manipulating text property types: prop_type_add({name}, {props}) define a new property type prop_type_change({name}, {props}) change an existing property type prop_type_delete({name} [, {props}]) delete a property type -prop_type_get([{name} [, {props}]) get property type values +prop_type_get([{name} [, {props}]]) get property type values prop_type_list([{props}]) get list of property types @@ -111,7 +111,7 @@ prop_add({lnum}, {col}, {props}) add a text property prop_clear({lnum} [, {lnum-end} [, {bufnr}]]) remove all text properties prop_find({props} [, {direction}]) search for a text property -prop_list({lnum} [, {props}) text properties in {lnum} +prop_list({lnum} [, {props}]) text properties in {lnum} prop_remove({props} [, {lnum} [, {lnum-end}]]) remove a text property @@ -291,7 +291,7 @@ prop_type_delete({name} [, {props}]) *prop_type_delete()* Can also be used as a |method|: > GetPropName()->prop_type_delete() -prop_type_get([{name} [, {props}]) *prop_type_get()* +prop_type_get([{name} [, {props}]]) *prop_type_get()* Returns the properties of property type {name}. This is a dictionary with the same fields as was given to prop_type_add(). diff --git a/runtime/doc/todo.txt b/runtime/doc/todo.txt index c7269216ed..abdd346adf 100644 --- a/runtime/doc/todo.txt +++ b/runtime/doc/todo.txt @@ -1,4 +1,4 @@ -*todo.txt* For Vim version 8.2. Last change: 2020 Apr 10 +*todo.txt* For Vim version 8.2. Last change: 2020 May 26 VIM REFERENCE MANUAL by Bram Moolenaar @@ -38,29 +38,59 @@ browser use: https://github.com/vim/vim/issues/1234 *known-bugs* -------------------- Known bugs and current work ----------------------- +Include src/po/vim.pot ? + Vim9 script: -func and partial types: -- check using func type with default arguments and varargs. - func(type, type?, ...): rettype -- Type checking arguments when calling :def function and test -- Calling unknown user function does not give proper error message: - assert_equal('123text', RefDef2Arg()) typo for "RetDef2Arg" -- "func" inside "vim9script" doesn't work? (Ben Jackson, #5670) -- :func inside vim9script must still use a:arg -- define function and create funcref in one step: - let ref = def(arg: type): rettype - body - enddef -Also: +Making everything work: +- possible memory leak in test_vim9_func through compile_nested_function. +- memory leaks in test_vim9_expr +- memory leaks in test_vim9_script +- Test that a script-local function in Vim9 script cannot be deleted. +- Make "true" and "false" work in vim9script +- Test that a function defined inside a :def function is local to that + function, g: functions can be defined and script-local functions cannot be + defined. +- make 0 == 'string' fail on the script level, like inside :def. +- Check that when using a user function name without prefix, it does not find + a global function. Prefixing g: is required. +- Compile: let [var, var] = expr +- Compile: for [key, value] in items(map) +- Assignment to dict doesn't work: + let ret: dict = #{} + ret[i] = string(i) +- Appending to dict item doesn't work: + let d[i] ..= value +- Compile replacement of :s command: s/pat/\=expr/ +- Compile redir to local variable: var_redir_start(). +- Compile builtin functions that access local variables: + islocked() +- Expand `=expr` in :next, :argedit, :argadd, :argdelete, :drop +- Expand `=expr` in :vimgrep, :vimgrepadd, :lvimgrep, :lvimgrepadd +- Expand `=expr` in :mkspell +- When evaluating constants for script variables, some functions could work: + has('asdf'), len('string') +- Support type for ":let"/":const" at script level for Vim9 script. + (Ben Jackson, #5671) + Can we share the code from ex_let_const() between direct execution and + compiling? +- Disallow unlet for local/script/imported vars +- Make "++nr" work. +- Make closures work: + - Create closure in a loop. Need to make a list of them. +- expandcmd() with `=expr` in filename uses legacy expression. +- eval_expr() in ex_cexpr() +- eval_expr() call in dbg_parsearg() and debuggy_find() +- has() is compiled as a constant, but some checks are dynamic. + Check for dynamic values, such as "gui_running". +New syntax and functionality: +Improve error checking: - "echo Func()" is an error if Func() does not return anything. +Also: +- For range: make table of first ASCII character with flag to quickly check if + it can be a Vim9 command. E.g. "+" can, but "." can't. - better implementation for partial and tests for that. - Make "g:imported = Export.exported" work in Vim9 script. - Make Foo.Bar() work to call the dict function. (#5676) -- make "let var: string" work in a vim9script. -- Disallow unlet for local/script/imported vars -- Support type for ":let"/":const" at script level for Vim9 script. - (Ben Jackson, #5671) -- Make "++nr" work. - Check that import in legacy script works and puts item in s: - Error in any command in "vim9script" aborts sourcing. - Find a way to test expressions in legacy and Vim9 script without duplication @@ -75,24 +105,37 @@ Also: map(list, SomeFunc) - Test: Function declared inside a :def function is local, disappears at the end of the function. Unless g: is used, just like with variables. -- Can we omit \ for line continuation inside (), {}, ? - Requires parsing while reading a function. Like fgetline in do_one_cmd()? - implement :type - import type declaration? - implement class - implement interface - predefined class: Promise +- implement enum - Make accessing varargs faster: arg[expr] EVAL expr LOADVARARG (varags idx) +Further improvements: +- compile options that are an expression, e.g. "expr:" in 'spellsuggest', + 'foldexpr', 'foldtext', 'printexpr', 'diffexpr', 'patchexpr', 'charconvert', + 'balloonexpr', 'includeexpr', 'indentexpr', 'formatexpr'. +- Make inline function work, to be used as a funcref: + let ref = def(arg: type): rettype + body + enddef +- compile get_lambda_tv() in popup_add_timeout() +- inline call to map() and filter() +- compile "skip" argument of searchpair() +- compile "expr" and "call" expression of a channel in channel_exe_cmd()? Popup windows: +- Can put focus in another window using API and "drop". (#6077) - With some sequence get get hidden finished terminal buffer. (#5768) Cannot close popup terminal (#5744) Buffer can't be wiped, gets status "aF". (#5764) Is buf->nwindows incorrect? - popup_clear() and popup_close() should close the terminal popup, and make the buffer hidden. #5745 +- Cursor not updated before a redraw, making it jump. (#5943) - With terminal in popup, allow for popup_hide() to temporarily hide it.? - Fire some autocommand event after a new popup window was created and positioned? PopupNew? Could be used to set some options or move it out of @@ -113,6 +156,8 @@ Popup windows: Text properties: - Patch to fix that split / join does not update properties properly (Axel Forsman, #5839) Alternative: #5875. +- :goto does not go to the right place when test properties are present. + (#5930) - "cc" does not call inserted_bytes(). (Axel Forsman, #5763) - Get E685 with a sequence of commands. (#5674) - Combining text property with 'cursorline' does not always work (Billie @@ -152,8 +197,16 @@ Terminal debugger: with another Vim instance. Terminal emulator window: +- When started with ":terminal ++close" and the shell exits but there is a + background process, the window remains open, because the channel still + exists (and output still shows). Perhaps close the window when an explicit + ++close was used? (#5931) +- Using "CTRL-W :confirm quite" and selecting "yes" should work like ":quit!". + (Harm te Hennepe, #6129) - When the job in the terminal doesn't use mouse events, let the scroll wheel scroll the scrollback, like a terminal does at the shell prompt. #2490 + A bit like using CTRL-W N first. + Jump back like with "a" when any key is typed. And use modeless selection. #2962 - Use CTRL-W CTRL-K to enter a digraph? #5371 - When Vim runs in the terminal and changes the title, the statusline needs to @@ -183,8 +236,10 @@ Terminal emulator window: conversions. Error numbers available: -E453, E454, E460, E489, E491, E565, E578, E610, E611, E653, -E654, E856, E857, E861, E900 +E453, E454, E489, E610, E611, E653, E856, E857, E861, E900 + +Patch to fix that typval related code is spread out. (Yegappan Lakshmanan, +#6093) Buffer autocommands are a bit inconsistent. Add a separate set of autocommands for the buffer lifecycle: @@ -198,26 +253,48 @@ The buffer list and windows are locked, no changes possible Patch to fix drawing error with DirectX. (James Grant, #5688) Causes flicker on resizing. -In gvim always set t_Co to 16777216 (#5903) +Patch to support ipv6 for channel. (Ozaki Kiichi, #5893) Patch to explain use of "%" in :!. (David Briscoe, #5591) Patch to improve Windows terminal support. (Nobuhiro Takasaki, #5546) Ready to include. +Patch to improve use of Lua path. (Prabir Shrestha, #6098) + +Patch to make exepath() work better on MS-Windows. (#6115) + Patch to add "-d" to xxd. (#5616) +Patch for the Haiku port: #5961 + Patch to add Turkish manual. (Emir Sarı, #5641) +Patch to add lua sleep function. (Prabir Shrestha, #6057) +Alternative: use vim.call and vim.fn: #6063 + +Patch to add getmarklist() (Yegappan, #6032) + +Patch to support different color for undercurl in cterm. +(Timur Celik, #6011) + Patch to support cindent option to handle pragmas differently. (Max Rumpf, #5468) +Patch to add ":syn foldlevel" to use fold level further down the line. +(Brad King, 2016 Oct 19, update 2017 Jan 30, now in #6087) + File marks merging has duplicates since 7.4.1925. (Ingo Karkat, #5733) -Running test_gui and test_gui_init with Motif sometimes kills the window -manager. Problem with Motif? Now test_gui crashes in submenu_change(). +"make test_gui" crashed in submenu_change(). Fix and remove workaround in +add_pixmap_args(). Athena is OK. Motif: Build on Ubuntu can't enter any text in dialog text fields. +Running test_gui and test_gui_init with Motif sometimes kills the window +manager. Problem with Motif? + +:map output does not clear the reset of the command line. +(#5623, also see #5962) Patch to properly break CJK lines: Anton Kochkov, #3875 Flag in 'formatoptions' is not used in the tests. @@ -225,6 +302,9 @@ Flag in 'formatoptions' is not used in the tests. Patch to add 'vtp' option. (#5344) Needs better docs. Is there a better name? +Patch to add argument to trim() to only trim start or end of a string. +(Yegappan, #6126) + undo result wrong: Masato Nishihata, #4798 Patch for Template string: #4491. New pull: #4634 @@ -233,7 +313,22 @@ Ready to include? Review the code. When 'lazyredraw' is set sometimes the title is not updated. (Jason Franklin, 2020 Feb 3) Looks like a race condition. -Patch to delete BeOS code. (#5817) +Patch to delete BeOS code. (#5817) Anyone who wants to keep it? + +With bash ":make" does not set v:shell_error. Possible solution: set +'shellpipe' to "2>&1| tee %s; exit ${PIPESTATUS[0]}" #5994 + +Using mode() when "/pat" is used in Visual mode returns "v" instead of "c", +which is not useful. Return "c/v" instead. And "c/o" when using "d/pat". +#6127 + +When 'fileignorecase' is set ":e testfile.c" works to edit TestFile.c, but +":find testfile.c" does not ignore case. +Might be related to #6088. + +When changing the crypt key the buffer should be considered modified. +Like when changing 'fileformat'. Save the old key in save_file_ff(). +(Ninu-Ciprian Marginean) Strange sequence of BufWipeout and BufNew events while doing omni-complete. (Paul Jolly, #5656) @@ -250,6 +345,8 @@ Patch to add function to return the text used in the quickfix window. Patch to add readdirex() (Ken Takata, #5619) +Wrong error when using local arglist. (Harm te Hennepe, #6133) + Request to support in mappings, similar to how Neovim does this. (Daniel Hahler, #4784) @@ -316,15 +413,13 @@ Python 3.8 doesn't work. (Antonios Hadjigeorgalis, #5509) The :syntax cchar value can only be a single character. It would be useful to support combining characters. (Charles Campbell) Also #4687 -Include Haiku port. (Adrien Destugues, Siarzhuk Zharski, 2013 Oct 24) -It can replace the BeOS code, which is likely not used anymore. -Now on github: #1856. Updated Oct 2017 -Got permission to include this under the Vim license. - "--cleanFOO" does not result in an error. (#5537) Add "t" action to settagstack(): truncate and add new entries. (#5405) +When 'relativenumber' is set the line just below a diff change doesn't get +updated. (#6138) + Result of synID() sometimes wrong in help files. (#5252) Status line is nut updated when splitting windows. (Marcin Szamotulski, #5496) @@ -1265,6 +1360,8 @@ sort() is not stable when using numeric/float sort (Nikolay Pavlov, 2016 Sep - Add ch_readlines(): for a channel in NL mode, reads as many lines as are available. Should be more efficient than looping over ch_read() with ch_status() to check for more. +- If buffer contents is changed in a callback, set w_redr_status so that it + gets redrawn in redraw_after_callback(). #6120 - Add a separate timeout for opening a socket. Currently it's fixed at 50 msec, which is too small for a remote connection. (tverniquet, #2130) - Problem with stderr on Windows? (Vincent Rischmann, 2016 Aug 31, #1026) @@ -1388,9 +1485,6 @@ Also with latest version. Cannot delete a file with square brackets with delete(). (#696) -Patch to add ":syn foldlevel" to use fold level further down the line. -(Brad King, 2016 Oct 19, update 2017 Jan 30) - Completion for input() does not expand environment variables. (chdiza, 2016 Jul 25, #948) diff --git a/runtime/doc/usr_08.txt b/runtime/doc/usr_08.txt index a5e21f3919..57287d0f43 100644 --- a/runtime/doc/usr_08.txt +++ b/runtime/doc/usr_08.txt @@ -402,7 +402,7 @@ Another way to start in diff mode can be done from inside Vim. Edit the "main.c" file, then make a split and show the differences: > :edit main.c - :vertical diffsplit main.c~ + :vertical diffsplit main.c~ The ":vertical" command is used to make the window split vertically. If you omit this, you will get a horizontal split. diff --git a/runtime/doc/usr_10.txt b/runtime/doc/usr_10.txt index d5799193f8..7898618b4e 100644 --- a/runtime/doc/usr_10.txt +++ b/runtime/doc/usr_10.txt @@ -687,7 +687,7 @@ with any motion command, with text objects and in Visual mode. lowercase. This can be shortened to "guu". "gUgU" is shortened to "gUU" and "g~g~" to "g~~". Example: > - g~~ + g~~ < Some GIRLS have Fun ----> sOME girls HAVE fUN ~ ============================================================================== diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt index e269ba24bd..46fea8e272 100644 --- a/runtime/doc/various.txt +++ b/runtime/doc/various.txt @@ -1,4 +1,4 @@ -*various.txt* For Vim version 8.2. Last change: 2020 Mar 19 +*various.txt* For Vim version 8.2. Last change: 2020 Apr 13 VIM REFERENCE MANUAL by Bram Moolenaar @@ -546,7 +546,7 @@ N *+X11* Unix only: can restore window title |X11| locked or the variable type is changed, then further command output messages will cause errors. To get the output of one command the |execute()| - function can be used. + function can be used instead of redirection. :redi[r] =>> {var} Append messages to an existing variable. Only string variables can be used. diff --git a/runtime/doc/vim9.txt b/runtime/doc/vim9.txt index dd2d510565..9a74b3ae7b 100644 --- a/runtime/doc/vim9.txt +++ b/runtime/doc/vim9.txt @@ -1,4 +1,4 @@ -*vim9.txt* For Vim version 8.2. Last change: 2020 Apr 09 +*vim9.txt* For Vim version 8.2. Last change: 2020 May 25 VIM REFERENCE MANUAL by Bram Moolenaar @@ -6,7 +6,7 @@ THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE -Vim9 script commands and expressions. +Vim9 script commands and expressions. *vim9* Most expression help is in |eval.txt|. This file is about the new syntax and features in Vim9 script. @@ -28,29 +28,33 @@ THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE -Vim script has been growing over time, while keeping backwards compatibility. -That means bad choices from the past often can't be changed. Execution is -quite slow, every line is parsed every time it is executed. +Vim script has been growing over time, while preserving backwards +compatibility. That means bad choices from the past often can't be changed +and compability with Vi restricts possible solutions. Execution is quite +slow, each line is parsed every time it is executed. -The main goal of Vim9 script is to drastically improve performance. An -increase in execution speed of 10 to 100 times can be expected. A secondary -goal is to avoid Vim-specific constructs and get closer to commonly used -programming languages, such as JavaScript, TypeScript and Java. +The main goal of Vim9 script is to drastically improve performance. This is +accomplished by compiling commands into instructions that can be efficiently +executed. An increase in execution speed of 10 to 100 times can be expected. + +A secondary goal is to avoid Vim-specific constructs and get closer to +commonly used programming languages, such as JavaScript, TypeScript and Java. The performance improvements can only be achieved by not being 100% backwards -compatible. For example, in a function the arguments are not available in the -"a:" dictionary, as creating that dictionary adds quite a lot of overhead. -Other differences are more subtle, such as how errors are handled. +compatible. For example, making function arguments available in the +"a:" dictionary adds quite a lot of overhead. In a Vim9 function this +dictionary is not available. Other differences are more subtle, such as how +errors are handled. The Vim9 script syntax and semantics are used in: - a function defined with the `:def` command - a script file where the first command is `vim9script` When using `:function` in a Vim9 script file the legacy syntax is used. -However, this is discouraged. +However, this can be confusing and is therefore discouraged. -Vim9 script and legacy Vim script can be mixed. There is no need to rewrite -old scripts, they keep working as before. +Vim9 script and legacy Vim script can be mixed. There is no requirement to +rewrite old scripts, they keep working as before. ============================================================================== @@ -62,26 +66,75 @@ Comments starting with # ~ In Vim script comments normally start with double quote. That can also be the start of a string, thus in many places it cannot be used. In Vim9 script a -comment can also start with #. Normally this is a command to list text with +comment can also start with #. In Vi this is a command to list text with numbers, but you can also use `:number` for that. > - let count = 0 # number of occurences of Ni! + let count = 0 # number of occurences + +To improve readability there must be a space between the command and the # +that starts a comment. Note that #{ is the start of a dictionary, therefore +it cannot start a comment. Vim9 functions ~ -`:def` has no extra arguments like `:function` does: "range", "abort", "dict" -or "closure". A `:def` function always aborts on an error, does not get a -range passed and cannot be a "dict" function. +A function defined with `:def` is compiled. Execution is many times faster, +often 10x to 100x times. -In the function body: -- Arguments are accessed by name, without "a:". -- There is no "a:" dictionary or "a:000" list. Variable arguments are defined - with a name and have a list type: > - def MyFunc(...itemlist: list) +Many errors are already found when compiling, before the function is executed. +The syntax is strict, to enforce code that is easy to read and understand. + +Compilation is done when the function is first called, or when the +`:defcompile` command is encountered in the script where the function was +defined. + +`:def` has no options like `:function` does: "range", "abort", "dict" or +"closure". A `:def` function always aborts on an error, does not get a range +passed and cannot be a "dict" function. + +The argument types and return type need to be specified. The "any" type can +be used, type checking will then be done at runtime, like with legacy +functions. + +Arguments are accessed by name, without "a:". There is no "a:" dictionary or +"a:000" list. + +Variable arguments are defined as the last argument, with a name and have a +list type, similar to Typescript. For example, a list of numbers: > + def MyFunc(...itemlist: list) for item in itemlist ... +Functions and variables are script-local by default ~ + +When using `:function` or `:def` to specify a new function at the script level +in a Vim9 script, the function is local to the script, as if "s:" was +prefixed. Using the "s:" prefix is optional. + +To define or use a global function or variable the "g:" prefix must be used. + +When using `:function` or `:def` to specify a new function inside a function, +the function is local to the function. It is not possible to define a +script-local function inside a function. It is possible to define a global +function, using the "g:" prefix. + +When referring to a function and no "s:" or "g:" prefix is used, Vim will +search for the function in this order: +- Local to the current scope and outer scopes up to the function scope. +- Local to the current script file. +- Imported functions, see `:import`. +In all cases the function must be defined before used. That is when it is +first called or when `:defcompile` causes the call to be compiled. + +The result is that functions and variables without a namespace can always be +found in the script, either defined there or imported. Global functions and +variables could be defined anywhere (good luck finding where!). + +Global functions can be still be defined and deleted at nearly any time. In +Vim9 script script-local functions are defined once when the script is sourced +and cannot be deleted or replaced. + + Variable declarations with :let and :const ~ Local variables need to be declared with `:let`. Local constants need to be @@ -114,8 +167,8 @@ The declaration must be done earlier: > endif echo inner -To intentionally use a variable that won't be available later, a block can be -used: > +To intentionally avoid a variable being available later, a block can be used: +> { let temp = 'temp' ... @@ -129,12 +182,12 @@ and without `:let`, because there is no rule about where they are declared. Variables cannot shadow previously defined variables. Variables may shadow Ex commands, rename the variable if needed. -Global variables must be prefixed with "g:", also at the script level. -However, global user defined functions are used without "g:". > +Global variables and user defined functions must be prefixed with "g:", also +at the script level. > vim9script let script_local = 'text' let g:global = 'value' - let Funcref = ThatFunction + let Funcref = g:ThatFunction Since "&opt = value" is now assigning a value to option "opt", ":&" cannot be used to repeat a `:substitute` command. @@ -339,7 +392,9 @@ THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE `:def`, but it is not possible to nest `:def` inside `:function`, for backwards compatibility. - [!] is used as with `:function`. + [!] is used as with `:function`. Note that in Vim9 + script script-local functions cannot be deleted or + redefined. *:enddef* :enddef End of a function defined with `:def`. @@ -350,6 +405,10 @@ variables can be accessed without the "s:" prefix. They must be defined before the function. If the script the function is defined in is legacy script, then script-local variables must be accessed with the "s:" prefix. + *:defc* *:defcompile* +:defc[ompile] Compile functions defined in the current script that + were not compiled yet. + This will report errors found during the compilation. *:disa* *:disassemble* :disa[ssemble] {func} Show the instructions generated for {func}. @@ -468,9 +527,12 @@ Then "myvar" will only exist in this file. While without `vim9script` it would be available as `g:myvar` from any other script and function. The variables at the file level are very much like the script-local "s:" -variables in legacy Vim script, but the "s:" is omitted. +variables in legacy Vim script, but the "s:" is omitted. And they cannot be +deleted. -In Vim9 script the global "g:" namespace can still be used as before. +In Vim9 script the global "g:" namespace can still be used as before. And the +"w:", "b:" and "t:" namespaces. These have in common that variables are not +declared and they can be deleted. A side effect of `:vim9script` is that the 'cpoptions' option is set to the Vim default value, like with: > diff --git a/runtime/doc/windows.txt b/runtime/doc/windows.txt index 6129b8d13b..2b01fb359d 100644 --- a/runtime/doc/windows.txt +++ b/runtime/doc/windows.txt @@ -1,4 +1,4 @@ -*windows.txt* For Vim version 8.2. Last change: 2020 Mar 19 +*windows.txt* For Vim version 8.2. Last change: 2020 May 10 VIM REFERENCE MANUAL by Bram Moolenaar @@ -291,9 +291,9 @@ CTRL-W q *CTRL-W_q* CTRL-W CTRL-Q *CTRL-W_CTRL-Q* Without {count}: Quit the current window. If {count} is given quit the {count} window. - - When quitting the last window (not counting a help window), - exit Vim. + *edit-window* + When quitting the last edit window (not counting help or + preview windows), exit Vim. When 'hidden' is set, and there is only one window for the current buffer, it becomes hidden. When 'hidden' is not set, @@ -312,8 +312,9 @@ CTRL-W CTRL-Q *CTRL-W_CTRL-Q* :+quit " quit the next window :+2quit " quit the second next window < - When closing a help window, Vim will try to restore the - previous window layout |:helpclose|. + When closing a help window, and this is not the only window, + Vim will try to restore the previous window layout, see + |:helpclose|. :q[uit]! :{count}q[uit]! @@ -335,9 +336,9 @@ CTRL-W c *CTRL-W_c* *:clo* *:close* changed and the [!] is used, the buffer becomes hidden (unless there is another window editing it). - When there is only one window in the current tab page and - there is another tab page, this closes the current tab page. - |tab-page|. + When there is only one |edit-window| in the current tab page + and there is another tab page, this closes the current tab + page. |tab-page|. This command fails when: *E444* - There is only one window on the screen. diff --git a/runtime/filetype.vim b/runtime/filetype.vim index be29691532..7157f092b6 100644 --- a/runtime/filetype.vim +++ b/runtime/filetype.vim @@ -1,7 +1,7 @@ " Vim support file to detect file types " " Maintainer: Bram Moolenaar -" Last Change: 2020 Apr 12 +" Last Change: 2020 May 07 " Listen very carefully, I will say this only once if exists("did_load_filetypes") @@ -1133,6 +1133,9 @@ au BufNewFile,BufRead pf.conf setf pf " Pam conf au BufNewFile,BufRead */etc/pam.conf setf pamconf +" Pam environment +au BufNewFile,BufRead pam_env.conf,.pam_environment setf pamenv + " PApp au BufNewFile,BufRead *.papp,*.pxml,*.pxsl setf papp @@ -1650,7 +1653,9 @@ au BufNewFile,BufRead */etc/systemd/system/*.d/*.conf setf systemd au BufNewFile,BufRead */.config/systemd/user/*.d/*.conf setf systemd " Systemd temp files au BufNewFile,BufRead */etc/systemd/system/*.d/.#* setf systemd +au BufNewFile,BufRead */etc/systemd/system/.#* setf systemd au BufNewFile,BufRead */.config/systemd/user/*.d/.#* setf systemd +au BufNewFile,BufRead */.config/systemd/user/.#* setf systemd " Synopsys Design Constraints au BufNewFile,BufRead *.sdc setf sdc diff --git a/runtime/ftplugin/dosbatch.vim b/runtime/ftplugin/dosbatch.vim index 070bdc4ba2..0c5cde2503 100644 --- a/runtime/ftplugin/dosbatch.vim +++ b/runtime/ftplugin/dosbatch.vim @@ -1,7 +1,7 @@ " Vim filetype plugin file " Language: MS-DOS .bat files " Maintainer: Mike Williams -" Last Change: 14th April 2019 +" Last Change: 7th May 2020 " Only do this when not done yet for this buffer if exists("b:did_ftplugin") @@ -19,12 +19,21 @@ setlocal comments=b:rem,b:@rem,b:REM,b:@REM,::: setlocal commentstring=::\ %s setlocal formatoptions-=t formatoptions+=rol +" Lookup DOS keywords using Windows command help. +if executable('help.exe') + if has('terminal') + setlocal keywordprg=:term\ help.exe + else + setlocal keywordprg=help.exe + endif +endif + " Define patterns for the browse file filter if has("gui_win32") && !exists("b:browsefilter") let b:browsefilter = "DOS Batch Files (*.bat, *.cmd)\t*.bat;*.cmd\nAll Files (*.*)\t*.*\n" endif -let b:undo_ftplugin = "setlocal comments< formatoptions<" +let b:undo_ftplugin = "setlocal comments< formatoptions< keywordprg<" \ . "| unlet! b:browsefiler" let &cpo = s:cpo_save diff --git a/runtime/ftplugin/fortran.vim b/runtime/ftplugin/fortran.vim index 5d42409fd4..385f1557de 100644 --- a/runtime/ftplugin/fortran.vim +++ b/runtime/ftplugin/fortran.vim @@ -1,7 +1,8 @@ " Vim settings file " Language: Fortran 2008 (and older: Fortran 2003, 95, 90, 77, 66) " Version: 0.50 -" Last Change: 2015 Nov. 30 +" Last Change: 2020 Apr 20 +" Patched By: Eisuke Kawashima " Maintainer: Ajit J. Thakkar ; " Usage: For instructions, do :help fortran-plugin from Vim " Credits: @@ -31,10 +32,10 @@ if !exists("b:fortran_fixed_source") elseif exists("fortran_fixed_source") " User guarantees fixed source form let b:fortran_fixed_source = 1 - elseif expand("%:e") ==? "f\<90\|95\|03\|08\>" + elseif expand("%:e") =~? '^f\%(90\|95\|03\|08\)$' " Free-form file extension defaults as in Intel ifort, gcc(gfortran), NAG, Pathscale, and Cray compilers let b:fortran_fixed_source = 0 - elseif expand("%:e") ==? "f\|f77\|for" + elseif expand("%:e") =~? '^\%(f\|f77\|for\)$' " Fixed-form file extension defaults let b:fortran_fixed_source = 1 else diff --git a/runtime/ftplugin/man.vim b/runtime/ftplugin/man.vim index f627035eb2..ab7f33f286 100644 --- a/runtime/ftplugin/man.vim +++ b/runtime/ftplugin/man.vim @@ -1,7 +1,8 @@ " Vim filetype plugin file " Language: man +" Maintainer: Jason Franklin " Maintainer: SungHyun Nam -" Last Change: 2020 Apr 13 +" Last Change: 2020 May 07 " To make the ":Man" command available before editing a manual page, source " this script from your startup vimrc file. diff --git a/runtime/ftplugin/masm.vim b/runtime/ftplugin/masm.vim new file mode 100644 index 0000000000..235469ac32 --- /dev/null +++ b/runtime/ftplugin/masm.vim @@ -0,0 +1,19 @@ +" Vim filetype plugin file +" Language: Microsoft Macro Assembler (80x86) +" Maintainer: Wu Yongwei +" Last Change: 2020-05-09 23:02:05 +0800 + +if exists("b:did_ftplugin") + finish +endif +let b:did_ftplugin = 1 + +let s:cpo_save = &cpo +set cpo&vim + +let b:undo_ftplugin = "setl iskeyword<" + +setlocal iskeyword=@,48-57,_,36,60,62,63,@-@ + +let &cpo = s:cpo_save +unlet s:cpo_save diff --git a/runtime/ftplugin/perl.vim b/runtime/ftplugin/perl.vim index e7acf654f3..603ba49502 100644 --- a/runtime/ftplugin/perl.vim +++ b/runtime/ftplugin/perl.vim @@ -1,9 +1,9 @@ " Vim filetype plugin file " Language: Perl " Maintainer: vim-perl -" Homepage: http://github.com/vim-perl/vim-perl -" Bugs/requests: http://github.com/vim-perl/vim-perl/issues -" Last Change: 2015-02-09 +" Homepage: https://github.com/vim-perl/vim-perl +" Bugs/requests: https://github.com/vim-perl/vim-perl/issues +" Last Change: 2020 Apr 15 if exists("b:did_ftplugin") | finish | endif let b:did_ftplugin = 1 diff --git a/runtime/ftplugin/perl6.vim b/runtime/ftplugin/perl6.vim index 5318df63bc..0467bea0c2 100644 --- a/runtime/ftplugin/perl6.vim +++ b/runtime/ftplugin/perl6.vim @@ -1,9 +1,9 @@ " Vim filetype plugin file " Language: Perl 6 " Maintainer: vim-perl -" Homepage: http://github.com/vim-perl/vim-perl -" Bugs/requests: http://github.com/vim-perl/vim-perl/issues -" Last Change: 2013-07-21 +" Homepage: https://github.com/vim-perl/vim-perl +" Bugs/requests: https://github.com/vim-perl/vim-perl/issues +" Last Change: 2020 Apr 15 " Contributors: Hinrik Örn Sigurðsson " " Based on ftplugin/perl.vim by Dan Sharp diff --git a/runtime/ftplugin/systemd.vim b/runtime/ftplugin/systemd.vim index 60b3fd996d..4c5c9a1dc1 100644 --- a/runtime/ftplugin/systemd.vim +++ b/runtime/ftplugin/systemd.vim @@ -1,7 +1,41 @@ " Vim filetype plugin file -" Language: systemd.unit(5) +" Language: systemd.unit(5) +" Keyword Lookup Support: Enno Nagel if !exists('b:did_ftplugin') " Looks a lot like dosini files. runtime! ftplugin/dosini.vim endif + +if !has('unix') + finish +endif + +if !has('gui_running') + command! -buffer -nargs=1 Sman silent exe '!' . KeywordLookup_systemd() | redraw! +elseif has('terminal') + command! -buffer -nargs=1 Sman silent exe 'term ' . KeywordLookup_systemd() +else + finish +endif + +if !exists('*KeywordLookup_systemd') + function KeywordLookup_systemd(keyword) abort + let matches = matchlist(getline(search('\v^\s*\[\s*.+\s*\]\s*$', 'nbWz')), '\v^\s*\[\s*(\k+).*\]\s*$') + if len(matches) > 1 + let section = matches[1] + return 'LESS= MANPAGER="less --pattern=''(^|,)\s+' . a:keyword . '=$'' --hilite-search" man ' . 'systemd.' . section + else + return 'LESS= MANPAGER="less --pattern=''(^|,)\s+' . a:keyword . '=$'' --hilite-search" man ' . 'systemd' + endif + endfunction +endif + +setlocal iskeyword+=- +setlocal keywordprg=:Sman + +if !exists('b:undo_ftplugin') || empty(b:undo_ftplugin) + let b:undo_ftplugin = 'setlocal keywordprg< iskeyword<' +else + let b:undo_ftplugin .= '| setlocal keywordprg< iskeyword<' +endif diff --git a/runtime/ftplugin/vim.vim b/runtime/ftplugin/vim.vim index 751a033045..150f54a54e 100644 --- a/runtime/ftplugin/vim.vim +++ b/runtime/ftplugin/vim.vim @@ -1,7 +1,7 @@ " Vim filetype plugin " Language: Vim " Maintainer: Bram Moolenaar -" Last Change: 2018 Aug 07 +" Last Change: 2020 May 17 " Only do this when not done yet for this buffer if exists("b:did_ftplugin") @@ -12,7 +12,7 @@ endif let b:did_ftplugin = 1 let s:cpo_save = &cpo -set cpo-=C +set cpo&vim if !exists('*VimFtpluginUndo') func VimFtpluginUndo() @@ -63,14 +63,14 @@ if !exists("no_plugin_maps") && !exists("no_vim_maps") let b:did_add_maps = 1 " Move around functions. - nnoremap [[ m':call search('^\s*fu\%[nction]\>', "bW") - vnoremap [[ m':exe "normal! gv"call search('^\s*fu\%[nction]\>', "bW") - nnoremap ]] m':call search('^\s*fu\%[nction]\>', "W") - vnoremap ]] m':exe "normal! gv"call search('^\s*fu\%[nction]\>', "W") - nnoremap [] m':call search('^\s*endf\%[unction]\>', "bW") - vnoremap [] m':exe "normal! gv"call search('^\s*endf\%[unction]\>', "bW") - nnoremap ][ m':call search('^\s*endf\%[unction]\>', "W") - vnoremap ][ m':exe "normal! gv"call search('^\s*endf\%[unction]\>', "W") + nnoremap [[ m':call search('^\s*\(fu\%[nction]\\|def\)\>', "bW") + vnoremap [[ m':exe "normal! gv"call search('^\s*\(fu\%[nction]\\|def\)\>', "bW") + nnoremap ]] m':call search('^\s*\(fu\%[nction]\\|def\)\>', "W") + vnoremap ]] m':exe "normal! gv"call search('^\s*\(fu\%[nction]\\|def\)\>', "W") + nnoremap [] m':call search('^\s*end\(f\%[unction]\\|def\)\>', "bW") + vnoremap [] m':exe "normal! gv"call search('^\s*end\(f\%[unction]\\|def\)\>', "bW") + nnoremap ][ m':call search('^\s*end\(f\%[unction]\\|def\)\>', "W") + vnoremap ][ m':exe "normal! gv"call search('^\s*end\(f\%[unction]\\|def\)\>', "W") " Move around comments nnoremap ]" :call search('^\(\s*".*\n\)\@ diff --git a/runtime/indent/fortran.vim b/runtime/indent/fortran.vim index 2ba69e86df..df55569f89 100644 --- a/runtime/indent/fortran.vim +++ b/runtime/indent/fortran.vim @@ -1,7 +1,8 @@ " Vim indent file " Language: Fortran 2008 (and older: Fortran 2003, 95, 90, and 77) " Version: 47 -" Last Change: 2016 Oct. 29 +" Last Change: 2020 Apr 20 +" Patched By: Eisuke Kawashima " Maintainer: Ajit J. Thakkar ; " Usage: For instructions, do :help fortran-indent from Vim " Credits: @@ -39,10 +40,10 @@ if !exists("b:fortran_fixed_source") elseif exists("fortran_fixed_source") " User guarantees fixed source form let b:fortran_fixed_source = 1 - elseif expand("%:e") ==? "f\<90\|95\|03\|08\>" + elseif expand("%:e") =~? '^f\%(90\|95\|03\|08\)$' " Free-form file extension defaults as in Intel ifort, gcc(gfortran), NAG, Pathscale, and Cray compilers let b:fortran_fixed_source = 0 - elseif expand("%:e") ==? "f\|f77\|for" + elseif expand("%:e") =~? '^\%(f\|f77\|for\)$' " Fixed-form file extension defaults let b:fortran_fixed_source = 1 else diff --git a/runtime/indent/perl.vim b/runtime/indent/perl.vim index 094d1d37ea..5fc8b7008a 100644 --- a/runtime/indent/perl.vim +++ b/runtime/indent/perl.vim @@ -1,9 +1,9 @@ " Vim indent file " Language: Perl 5 " Maintainer: vim-perl -" Homepage: http://github.com/vim-perl/vim-perl -" Bugs/requests: http://github.com/vim-perl/vim-perl/issues -" Last Change: 2017-01-04 +" Homepage: https://github.com/vim-perl/vim-perl +" Bugs/requests: https://github.com/vim-perl/vim-perl/issues +" Last Change: 2020 Apr 15 " Suggestions and improvements by : " Aaron J. Sherman (use syntax for hints) diff --git a/runtime/indent/perl6.vim b/runtime/indent/perl6.vim index 8561c8c58c..51c7923182 100644 --- a/runtime/indent/perl6.vim +++ b/runtime/indent/perl6.vim @@ -1,9 +1,9 @@ " Vim indent file " Language: Perl 6 " Maintainer: vim-perl -" Homepage: http://github.com/vim-perl/vim-perl -" Bugs/requests: http://github.com/vim-perl/vim-perl/issues -" Last Change: 2017 Jun 13 +" Homepage: https://github.com/vim-perl/vim-perl +" Bugs/requests: https://github.com/vim-perl/vim-perl/issues +" Last Change: 2020 Apr 15 " Contributors: Andy Lester " Hinrik Örn Sigurðsson " diff --git a/runtime/indent/python.vim b/runtime/indent/python.vim index e53987a0de..f9236e63c7 100644 --- a/runtime/indent/python.vim +++ b/runtime/indent/python.vim @@ -28,6 +28,11 @@ set cpo&vim let s:maxoff = 50 " maximum number of lines to look backwards for () +" See if the specified line is already user-dedented from the expected value. +function s:Dedented(lnum, expected) + return indent(a:lnum) <= a:expected - shiftwidth() +endfunction + function GetPythonIndent(lnum) " If this line is explicitly joined: If the previous line was also joined, @@ -158,12 +163,12 @@ function GetPythonIndent(lnum) " If the previous line was a stop-execution statement... if getline(plnum) =~ '^\s*\(break\|continue\|raise\|return\|pass\)\>' " See if the user has already dedented - if indent(a:lnum) > indent(plnum) - shiftwidth() - " If not, recommend one dedent - return indent(plnum) - shiftwidth() + if s:Dedented(a:lnum, indent(plnum)) + " If so, trust the user + return -1 endif - " Otherwise, trust the user - return -1 + " If not, recommend one dedent + return indent(plnum) - shiftwidth() endif " If the current line begins with a keyword that lines up with "try" @@ -191,7 +196,7 @@ function GetPythonIndent(lnum) endif " Or the user has already dedented - if indent(a:lnum) <= plindent - shiftwidth() + if s:Dedented(a:lnum, plindent) return -1 endif @@ -203,7 +208,12 @@ function GetPythonIndent(lnum) " + c) " here if parlnum > 0 - return plindent + " ...unless the user has already dedented + if s:Dedented(a:lnum, plindent) + return -1 + else + return plindent + endif endif return -1 diff --git a/runtime/indent/sshconfig.vim b/runtime/indent/sshconfig.vim new file mode 100644 index 0000000000..b456a9e3aa --- /dev/null +++ b/runtime/indent/sshconfig.vim @@ -0,0 +1,34 @@ +" Vim indent file +" Language: ssh config file +" Maintainer: JasonKim +" Last Change: 2020 May 16 + +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +setlocal autoindent +setlocal indentexpr=GetSshconfigIndent(v:lnum) +setlocal indentkeys=o,O,*,0=~host\ ,0=~match\ ,0#,!^F + +let b:undo_indent = "setlocal autoindent< indentexpr< indentkeys<" + +if exists("*GetSshconfigIndent") + finish +endif + +function GetSshconfigIndent(lnum) + let sw = shiftwidth() + let prev_lnum = prevnonblank(a:lnum - 1) + let curr_lnum = a:lnum + let prev_line = getline(prev_lnum) + let curr_line = getline(curr_lnum) + if curr_line =~? '^\s*\(host\|match\)\s' + return 0 + elseif prev_line =~? '^\s*\(host\|match\)\s' + return sw + else + return indent(prev_lnum) + endif +endfunction diff --git a/runtime/indent/testdir/runtest.vim b/runtime/indent/testdir/runtest.vim index b234a1ad94..6bbd33cacd 100644 --- a/runtime/indent/testdir/runtest.vim +++ b/runtime/indent/testdir/runtest.vim @@ -10,6 +10,7 @@ filetype indent on syn on set nowrapscan set report=9999 +set modeline au! SwapExists * call HandleSwapExists() func HandleSwapExists() diff --git a/runtime/indent/testdir/sshconfig.in b/runtime/indent/testdir/sshconfig.in new file mode 100644 index 0000000000..87b998e465 --- /dev/null +++ b/runtime/indent/testdir/sshconfig.in @@ -0,0 +1,53 @@ +# vim: set filetype=sshconfig shiftwidth=4 expandtab : + +# START_INDENT +Host myhost +User myuser +PasswordAuthentication no +# END_INDENT + +# START_INDENT +Host aaa +User bbb +Host ccc +Host ddd +# END_INDENT + +# START_INDENT +host aaa +HOST bbb +hoSt ccc +match ddd +MATCH eee +MatCH fff +# END_INDENT + +# START_INDENT +Host aaa +User host +PasswordAuthentication no +Host * +User user +PasswordAuthentication no +Host match +User bbb +# END_INDENT + +# START_INDENT +Host tab +User myuser +# END_INDENT + +# START_INDENT +Host mix +User myuser +# END_INDENT + +# START_INDENT +Host aaa +User bbb +Match ccc +User ddd +HostKeyAlgorithms ssh-ed25519 +Match eee +# END_INDENT diff --git a/runtime/indent/testdir/sshconfig.ok b/runtime/indent/testdir/sshconfig.ok new file mode 100644 index 0000000000..b24b7cf4e1 --- /dev/null +++ b/runtime/indent/testdir/sshconfig.ok @@ -0,0 +1,53 @@ +# vim: set filetype=sshconfig shiftwidth=4 expandtab : + +# START_INDENT +Host myhost + User myuser + PasswordAuthentication no +# END_INDENT + +# START_INDENT +Host aaa + User bbb +Host ccc +Host ddd +# END_INDENT + +# START_INDENT +host aaa +HOST bbb +hoSt ccc +match ddd +MATCH eee +MatCH fff +# END_INDENT + +# START_INDENT +Host aaa + User host + PasswordAuthentication no +Host * + User user + PasswordAuthentication no +Host match + User bbb +# END_INDENT + +# START_INDENT +Host tab + User myuser +# END_INDENT + +# START_INDENT +Host mix + User myuser +# END_INDENT + +# START_INDENT +Host aaa + User bbb +Match ccc + User ddd + HostKeyAlgorithms ssh-ed25519 +Match eee +# END_INDENT diff --git a/runtime/indent/tex.vim b/runtime/indent/tex.vim index a748cfbb40..8a44ade1ac 100644 --- a/runtime/indent/tex.vim +++ b/runtime/indent/tex.vim @@ -64,14 +64,17 @@ " style) is supported. Thanks Miles Wheeler for reporting. " 2018/02/07 by Yichao Zhou " (*) Make indentation more smart in the normal mode +" 2020/04/26 by Yichao Zhou +" (*) Fix a bug related to \[ & \]. Thanks Manuel Boni for +" reporting. " " }}} " Document: {{{ " -" To set the following options (ok, currently it's just one), add a line like -" let g:tex_indent_items = 1 -" to your ~/.vimrc. +" For proper latex experience, please put +" let g:tex_flavor = "latex" +" into your vimrc. " " * g:tex_indent_brace " @@ -184,13 +187,18 @@ function! GetTeXIndent() " {{{ let line = substitute(getline(lnum), '\s*%.*', '','g') " last line let cline = substitute(getline(v:lnum), '\s*%.*', '', 'g') " current line + let ccol = 1 + while cline[ccol] =~ '\s' + let ccol += 1 + endwhile + " We are in verbatim, so do what our user what. - if synIDattr(synID(v:lnum, indent(v:lnum), 1), "name") == "texZone" + if synIDattr(synID(v:lnum, ccol, 1), "name") == "texZone" if empty(cline) return indent(lnum) else return indent(v:lnum) - end + endif endif if lnum == 0 @@ -253,13 +261,13 @@ function! GetTeXIndent() " {{{ let stay = 0 endif - if cline =~ '^\s*\\\?[\]}]' && s:CheckPairedIsLastCharacter(v:lnum, indent(v:lnum)) + if cline =~ '^\s*\\\?[\]}]' && s:CheckPairedIsLastCharacter(v:lnum, ccol) let ind -= shiftwidth() let stay = 0 endif if line !~ '^\s*\\\?[\]}]' - for i in range(indent(lnum)+1, strlen(line)-1) + for i in range(1, strlen(line)-1) let char = line[i] if char == ']' || char == '}' if s:CheckPairedIsLastCharacter(lnum, i) diff --git a/runtime/lang/menu_ca_es.latin1.vim b/runtime/lang/menu_ca_es.latin1.vim index 8c0a9e9a61..6e30eef9df 100644 --- a/runtime/lang/menu_ca_es.latin1.vim +++ b/runtime/lang/menu_ca_es.latin1.vim @@ -79,7 +79,7 @@ menutrans &Global\ Settings Opcions\ &globals menutrans Never &Mai menutrans Block\ Selection &Selecció\ de\ blocs menutrans Insert\ mode Mode\ d'&inserció - menutrans Block\ and\ Insert &Blocs i inserció + menutrans Block\ and\ Insert &Blocs\ i\ inserció menutrans Always S&empre menutrans Toggle\ Insert\ &Mode:set\ im! Mode\ d'&inserció:set\ im! menutrans Toggle\ Vi\ C&ompatible:set\ cp! Co&mpatible\ amb\ Vi:set\ cp! diff --git a/runtime/lang/menu_chinese_gb.936.vim b/runtime/lang/menu_chinese_gb.936.vim index d96ab37802..f20989f4c8 100644 --- a/runtime/lang/menu_chinese_gb.936.vim +++ b/runtime/lang/menu_chinese_gb.936.vim @@ -1,7 +1,7 @@ " Menu Translations: Simplified Chinese " Maintainer: Shun Bai " Previous Maintainer: Yuheng Xie -" Last Change: 2019-09-10 +" Last Change: 2020 Apr 23 " Quit when menu translations have already been done. if exists("did_menu_trans") @@ -122,7 +122,7 @@ menutrans Toggle\ &C-Style\ Indenting:set\ cin! " other options menutrans &Shiftwidth Ëõ½ø¿í¶È(&S) -menutrans Soft\ &Tabstop ÈíÖÆ±íλ¿í¶È(Soft Tabstop)(&T) +menutrans Soft\ &Tabstop ÈíÖÆ±íλ¿í¶È(Soft\ Tabstop)(&T) menutrans Te&xt\ Width\.\.\. Îı¾¿í¶È(&X)\.\.\. menutrans &File\ Format\.\.\. Îļþ¸ñʽ(&F)\.\.\. @@ -435,8 +435,8 @@ menutrans Set\ '&filetype'\ Too Ò² menutrans Sorting\ Method ÅÅÐò·½Ê½ " Netrw.Style.Sorting Method menuitems {{{3 menutrans Names ÎļþÃûs - menutrans Times ÐÞ¸Äʱ¼äs - menutrans Sizes ´óСs + menutrans Times ÐÞ¸Äʱ¼äs + menutrans Sizes ´óСs menutrans Extens À©Õ¹Ãûs " }}} " }}} diff --git a/runtime/lang/menu_cs_cz.iso_8859-2.vim b/runtime/lang/menu_cs_cz.iso_8859-2.vim index 410d548ee1..1abf0c35e2 100644 --- a/runtime/lang/menu_cs_cz.iso_8859-2.vim +++ b/runtime/lang/menu_cs_cz.iso_8859-2.vim @@ -110,7 +110,7 @@ menutrans Build\ &Tags\ File &Vytvo if has("spell") menutrans &Spelling &Kontrola\ pravopisu menutrans &Spell\ Check\ On &Zapnout\ kontrolu\ pravopisu - menutrans Spell\ Check\ &Off &Vypnout \kontrolu\ pravopisu + menutrans Spell\ Check\ &Off &Vypnout\ kontrolu\ pravopisu menutrans To\ &Next\ error]s &Dal¹í\ chyba]s menutrans To\ &Previous\ error[s &Pøedchozí\ chyba[s menutrans Suggest\ &Correctionsz= &Navrhnout\ opravyz= diff --git a/runtime/lang/menu_cs_cz.utf-8.vim b/runtime/lang/menu_cs_cz.utf-8.vim index 91a8eccd46..a7be2c8b39 100644 --- a/runtime/lang/menu_cs_cz.utf-8.vim +++ b/runtime/lang/menu_cs_cz.utf-8.vim @@ -110,7 +110,7 @@ menutrans Build\ &Tags\ File &VytvoÅ™it\ soubor\ tagů if has("spell") menutrans &Spelling &Kontrola\ pravopisu menutrans &Spell\ Check\ On &Zapnout\ kontrolu\ pravopisu - menutrans Spell\ Check\ &Off &Vypnout \kontrolu\ pravopisu + menutrans Spell\ Check\ &Off &Vypnout\ kontrolu\ pravopisu menutrans To\ &Next\ error]s &Další\ chyba]s menutrans To\ &Previous\ error[s &PÅ™edchozí\ chyba[s menutrans Suggest\ &Correctionsz= &Navrhnout\ opravyz= diff --git a/runtime/lang/menu_czech_czech_republic.1250.vim b/runtime/lang/menu_czech_czech_republic.1250.vim index f9c85d038a..9502288ed2 100644 --- a/runtime/lang/menu_czech_czech_republic.1250.vim +++ b/runtime/lang/menu_czech_czech_republic.1250.vim @@ -110,7 +110,7 @@ menutrans Build\ &Tags\ File &Vytvo if has("spell") menutrans &Spelling &Kontrola\ pravopisu menutrans &Spell\ Check\ On &Zapnout\ kontrolu\ pravopisu - menutrans Spell\ Check\ &Off &Vypnout \kontrolu\ pravopisu + menutrans Spell\ Check\ &Off &Vypnout\ kontrolu\ pravopisu menutrans To\ &Next\ error]s &Další\ chyba]s menutrans To\ &Previous\ error[s &Pøedchozí\ chyba[s menutrans Suggest\ &Correctionsz= &Navrhnout\ opravyz= diff --git a/runtime/lang/menu_czech_czech_republic.ascii.vim b/runtime/lang/menu_czech_czech_republic.ascii.vim index 1c4fb3ed8f..e7c2c43a4b 100644 --- a/runtime/lang/menu_czech_czech_republic.ascii.vim +++ b/runtime/lang/menu_czech_czech_republic.ascii.vim @@ -110,7 +110,7 @@ menutrans Build\ &Tags\ File &Vytvorit\ soubor\ tagu if has("spell") menutrans &Spelling &Kontrola\ pravopisu menutrans &Spell\ Check\ On &Zapnout\ kontrolu\ pravopisu - menutrans Spell\ Check\ &Off &Vypnout \kontrolu\ pravopisu + menutrans Spell\ Check\ &Off &Vypnout\ kontrolu\ pravopisu menutrans To\ &Next\ error]s &Dalsi\ chyba]s menutrans To\ &Previous\ error[s &Predchozi\ chyba[s menutrans Suggest\ &Correctionsz= &Navrhnout\ opravyz= diff --git a/runtime/lang/menu_da.utf-8.vim b/runtime/lang/menu_da.utf-8.vim index 751dad0947..a11213c05c 100644 --- a/runtime/lang/menu_da.utf-8.vim +++ b/runtime/lang/menu_da.utf-8.vim @@ -1,6 +1,6 @@ " Menu Translations: Danish " Maintainer: scootergrisen -" Last Change: 2018 Aug 17 +" Last Change: 2020 Apr 23 " Quit when menu translations have already been done. if exists("did_menu_trans") @@ -390,7 +390,7 @@ menut Previewp ForhÃ¥ndsvisp menut Edit\ File\ Hiding\ List Rediger\ liste\ til\ filskjulning menut Edit\ Sorting\ SequenceS Rediger\ sorteringssekvensS menut Quick\ Hide/Unhide\ Dot\ Filesgh Hurtig\ skjul/vis\ punktum-filergh -menut Refresh\ Listing Genopfrisk\ oplistning\ ikke sikker det med \ er korrekt +menut Refresh\ Listing Genopfrisk\ oplistning\\ ikke\ sikker\ det\ med\ er\ korrekt menut Settings/Options:NetrwSettings Indstillinger/valgmuligheder menut Delete\ File/DirectoryD Slet\ fil/mappeD @@ -406,10 +406,10 @@ menut In\ New\ Vertical\ Windowv I\ nyt\ lodret\ vinduev menut Explore Gennemse menut Directory\ Name Mappenavn:Explore -menut Filenames\ Matching\ Pattern\ (curdir\ only):Explore\ */ test29:Explore */ -menut Filenames\ Matching\ Pattern\ (+subdirs):Explore\ **/ test30:Explore **/ -menut Files\ Containing\ String\ Pattern\ (curdir\ only):Explore\ *// test31:Explore *// -menut Files\ Containing\ String\ Pattern\ (+subdirs):Explore\ **// test32:Explore **// +menut Filenames\ Matching\ Pattern\ (curdir\ only):Explore\ */ test29:Explore\ */ +menut Filenames\ Matching\ Pattern\ (+subdirs):Explore\ **/ test30:Explore\ **/ +menut Files\ Containing\ String\ Pattern\ (curdir\ only):Explore\ *// test31:Explore\ *// +menut Files\ Containing\ String\ Pattern\ (+subdirs):Explore\ **// test32:Explore\ **// menut Next\ Match:Nexplore Næste\ match:Nexplore menut Prev\ Match:Pexplore Forrige\ match:Pexplore diff --git a/runtime/lang/menu_de_de.latin1.vim b/runtime/lang/menu_de_de.latin1.vim index 3079012ff4..d836118ea1 100644 --- a/runtime/lang/menu_de_de.latin1.vim +++ b/runtime/lang/menu_de_de.latin1.vim @@ -188,7 +188,7 @@ menutrans Set\ '&filetype'\ too Auch\ '&filetype'\ setzen menutrans &Off &Aus menutrans &Manual &Manuell menutrans A&utomatic A&utomatisch -menutrans on/off\ for\ &This\ file An/Aus (diese\ &Datei) +menutrans on/off\ for\ &This\ file An/Aus\ (diese\ &Datei) menutrans Co&lor\ test Test\ der\ Farben menutrans &Highlight\ test Test\ der\ Un&terstreichungen menutrans &Convert\ to\ HTML Konvertieren\ nach\ &HTML diff --git a/runtime/lang/menu_fi_fi.latin1.vim b/runtime/lang/menu_fi_fi.latin1.vim index 6a2c1e9053..c68f232eec 100644 --- a/runtime/lang/menu_fi_fi.latin1.vim +++ b/runtime/lang/menu_fi_fi.latin1.vim @@ -1,6 +1,6 @@ " Menu Translations: Finnish " Maintainer: Flammie Pirinen -" Last Change: 2012 May 01 +" Last Change: 2020 Apr 23 " Quit when menu translations have already been done. if exists("did_menu_trans") @@ -70,7 +70,7 @@ menutrans &Context\ lines &Huomioitavat\ kontekstirivit " Subsubmenu: " Accels: ELSOA menutrans &Virtual\ Edit &Virtuaalimuokkaus -menutrans Never &Ei koskaan +menutrans Never &Ei\ koskaan menutrans Block\ Selection &Lohkovalinta menutrans Insert\ mode &Syöttötila menutrans Block\ and\ Insert L&ohkosyöttötila @@ -95,7 +95,7 @@ menutrans F&ile\ Settings Tiedostoasetu&kset menutrans Toggle\ Line\ &Numbering:set\ nu! Rivi&numerointi:set\ nu! menutrans Toggle\ &List\ Mode:set\ list! &Listaustila:set\ list! menutrans Toggle\ Line\ &Wrap:set\ wrap! &Rivitys:set\ wrap! -menutrans Toggle\ W&rap\ at\ word:set\ lbr! &Sanoittainen rivitys:set\ lbr! +menutrans Toggle\ W&rap\ at\ word:set\ lbr! &Sanoittainen\ rivitys:set\ lbr! menutrans Toggle\ &expand-tab:set\ et! Muuta\ &tabit\ väleiksi:set\ et! menutrans Toggle\ &auto-indent:set\ ai! &Automaattinen\ sisennys:set\ ai! menutrans Toggle\ &C-indenting:set\ cin! &C-kielen\ sisennys:set\ cin! @@ -111,7 +111,7 @@ let g:menutrans_fileformat_choices = " &Unix \n &Dos \n &Mac \n &Peru " menutrans C&olor\ Scheme &Väriteema menutrans &Keymap &Näppäinkartta -menutrans None Ei mikään +menutrans None Ei\ mikään menutrans Select\ Fo&nt\.\.\. Valitse\ &fontti\.\.\. diff --git a/runtime/lang/menu_hu_hu.iso_8859-2.vim b/runtime/lang/menu_hu_hu.iso_8859-2.vim index c7821d2b32..27c460f3bf 100644 --- a/runtime/lang/menu_hu_hu.iso_8859-2.vim +++ b/runtime/lang/menu_hu_hu.iso_8859-2.vim @@ -1,7 +1,7 @@ " Menu Translations: Hungarian (Magyar) " Original Translation: Zoltán Árpádffy " Maintained By: Kontra Gergely -" Last Change: 2012 May 01 +" Last Change: 2020 Apr 23 " I'm working on defining (unaccented) hotkeys for everything. " I want to remove y and z hotkeys, because on the hungarian keymap they're at " a differrent place. @@ -68,7 +68,7 @@ menutrans &Paste"+gP &Beilleszt menutrans Put\ &Before[p Berakás\ e&lé[p menutrans Put\ &After]p Berakás\ &mögé]p menutrans &Deletex &Törlésx -menutrans &Select\ allggVG A&z\ összes kijelöléseggvG +menutrans &Select\ allggVG A&z\ összes\ kijelöléseggvG menutrans &Find\.\.\. Ke&resés\.\.\. menutrans Find\ and\ Rep&lace\.\.\. Keresés\ és\ c&sere\.\.\. menutrans Find\ and\ Rep&lace:%s Keresés\ és\ c&sere:%s diff --git a/runtime/lang/menu_hu_hu.utf-8.vim b/runtime/lang/menu_hu_hu.utf-8.vim index f3adf91882..092abc0857 100644 --- a/runtime/lang/menu_hu_hu.utf-8.vim +++ b/runtime/lang/menu_hu_hu.utf-8.vim @@ -1,7 +1,7 @@ " Menu Translations: Hungarian (Magyar) " Original Translation: Zoltán Ãrpádffy " Maintained By: Kontra Gergely -" Last Change: 2012 May 01 +" Last Change: 2020 Apr 23 " " This file was converted from menu_hu_hu.iso_8859-2.vim. See there for " remarks. @@ -52,7 +52,7 @@ menutrans &Paste"+gP &Beillesztés"+gP menutrans Put\ &Before[p Berakás\ e&lé[p menutrans Put\ &After]p Berakás\ &mögé]p menutrans &Deletex &Törlésx -menutrans &Select\ allggVG A&z\ összes kijelöléseggvG +menutrans &Select\ allggVG A&z\ összes\ kijelöléseggvG menutrans &Find\.\.\. Ke&resés\.\.\. menutrans Find\ and\ Rep&lace\.\.\. Keresés\ és\ c&sere\.\.\. menutrans Find\ and\ Rep&lace:%s Keresés\ és\ c&sere:%s diff --git a/runtime/lang/menu_is_is.latin1.vim b/runtime/lang/menu_is_is.latin1.vim index 28394e07c9..9616c6cfb4 100644 --- a/runtime/lang/menu_is_is.latin1.vim +++ b/runtime/lang/menu_is_is.latin1.vim @@ -59,7 +59,7 @@ menutrans Startup\ &Settings R menutrans Toggle\ Pattern\ &Highlight:set\ hls! Munsturauðkenning\ á\/af:set\ hls! menutrans Toggle\ &Ignoring\ Case:set\ ic! Hunsa\ há-lágstafi\ á\/af:set\ ic! -menutrans Toggle\ &Showing\ Matched\ Pairs:set\ sm! Sýna\ Pörun á\/af:set\ sm! +menutrans Toggle\ &Showing\ Matched\ Pairs:set\ sm! Sýna\ Pörun\ á\/af:set\ sm! menutrans &Context\ lines Samhengislínur @@ -70,7 +70,7 @@ menutrans Insert\ mode Innskotshamur menutrans Block\ and\ Insert Bálkval\ og\ Innskotshamur menutrans Always Alltaf menutrans Toggle\ Insert\ &Mode:set\ im! Innskotshamur\ á\/af:set\ im! -menutrans Toggle\ Vi\ C&ompatibility:set\ cp! Vi\ Samhæfanleiki á\/af:set\ cp! +menutrans Toggle\ Vi\ C&ompatibility:set\ cp! Vi\ Samhæfanleiki\ á\/af:set\ cp! menutrans Search\ &Path\.\.\. Leita\ í\ Slóð\.\.\. menutrans Ta&g\ Files\.\.\. Merkja\ Skrár\.\.\. @@ -90,7 +90,7 @@ menutrans Toggle\ &List\ Mode:set\ list! Listahamur\ menutrans Toggle\ Line\ &Wrapping:set\ wrap! Línuhlaup\ á\/af:set\ wrap! menutrans Toggle\ W&rapping\ at\ word:set\ lbr! Línuhlaup\ á\ orði\ á\/af:set\ lbr! menutrans Toggle\ Tab\ &Expanding:set\ et! Tab-víkkun\ á\/af:set\ et! -menutrans Toggle\ &Auto Indenting:set\ ai! Sjálfvirkur\ Inndráttur\ á\/af:set\ ai! +menutrans Toggle\ &Auto\ Indenting:set\ ai! Sjálfvirkur\ Inndráttur\ á\/af:set\ ai! menutrans Toggle\ &C-Style\ Indenting:set\ cin! C-Inndráttur\ á\/af:set\ cin! " other options diff --git a/runtime/lang/menu_it_it.latin1.vim b/runtime/lang/menu_it_it.latin1.vim index 8dec38bb14..927c3c9e67 100644 --- a/runtime/lang/menu_it_it.latin1.vim +++ b/runtime/lang/menu_it_it.latin1.vim @@ -2,7 +2,7 @@ " Maintainer: Antonio Colombo " Vlad Sandrini " Luciano Montanaro -" Last Change: 2018 May 16 +" Last Change: 2020 Apr 23 " Quit when menu translations have already been done. if exists("did_menu_trans") @@ -116,8 +116,8 @@ menut Toggle\ &List\ Mode:set\ list! Modo\ &List\ S menut Toggle\ Line\ &Wrapping:set\ wrap! Linee\ &Continuate\ Sì/No:set\ wrap! menut Toggle\ W&rapping\ at\ word:set\ lbr! A\ capo\ alla\ &Parola\ Sì/No:set\ lbr! menut Toggle\ Tab\ &expanding:set\ et! &Espandi\ Tabulazione\ Sì/No:set\ et! -menut Toggle\ &Auto\ Indenting:set\ ai! Indentazione\ &Automatica\ Sì/No:set ai! -menut Toggle\ &C-Style\ Indenting:set\ cin! Indentazione\ stile\ &C\ Sì/No:set cin! +menut Toggle\ &Auto\ Indenting:set\ ai! Indentazione\ &Automatica\ Sì/No:set\ ai! +menut Toggle\ &C-Style\ Indenting:set\ cin! Indentazione\ stile\ &C\ Sì/No:set\ cin! " -SEP2- menut &Shiftwidth &Spazi\ rientranza "menut &Shiftwidth.2:set\ sw=2\ sw? &Spazi\ rientranza.2:set\ sw=2\ sw? @@ -360,8 +360,8 @@ menut Copy Copia menut Paste Incolla " -sep3- menut Find Cerca -menut FindNext Cerca Successivo -menut FindPrev Cerca Precedente +menut FindNext Cerca\ Successivo +menut FindPrev Cerca\ Precedente menut Replace Sostituisci " -sep4- menut New Nuova\ finestra diff --git a/runtime/lang/menu_no_no.latin1.vim b/runtime/lang/menu_no_no.latin1.vim index a64e343445..1a5bb4011a 100644 --- a/runtime/lang/menu_no_no.latin1.vim +++ b/runtime/lang/menu_no_no.latin1.vim @@ -1,6 +1,6 @@ " Menu Translations: Norwegian / Norsk (Bokmål) " Maintainer: Øyvind A. Holm -" Last Change: 2012 May 01 +" Last Change: 2020 Apr 23 " menu_no_no.latin1.vim 289 2004-05-16 18:00:52Z sunny " Quit when menu translations have already been done. @@ -46,7 +46,7 @@ menutrans &Edit &Rediger menutrans Settings\ &Window &Innstillinger menutrans &Global\ Settings Glo&bale\ innstillinger menutrans Toggle\ Pattern\ &Highlight:set\ hls! &Utheving\ av\ søketekst\ av/på:set\ hls! - menutrans Toggle\ &Ignore-case:set\ ic! &Forskjell\ mellom\ store/små bokstaver\ av/på:set\ ic! + menutrans Toggle\ &Ignore-case:set\ ic! &Forskjell\ mellom\ store/små\ bokstaver\ av/på:set\ ic! menutrans Toggle\ &Showmatch:set\ sm! &Indikering\ av\ samsvarende\ parentes\ av/på:set\ sm! menutrans &Context\ lines &Kontekstlinjer menutrans &Virtual\ Edit Vi&rtuell\ redigering diff --git a/runtime/lang/menu_pt_br.vim b/runtime/lang/menu_pt_br.vim index f4980ef5ac..1e425008de 100644 --- a/runtime/lang/menu_pt_br.vim +++ b/runtime/lang/menu_pt_br.vim @@ -1,6 +1,6 @@ " Menu Translations: Português do Brasil " Maintainer: José de Paula -" Last Change: 2012 May 01 +" Last Change: 2020 Apr 23 " " Quit when menu translations have already been done. @@ -101,9 +101,9 @@ menutrans Toggle\ Line\ &Numbering:set\ nu! Ativar/Desativar\ &numera menutrans Toggle\ &List\ Mode:set\ list! Ativar/Desativar\ modo\ &list:set\ list! menutrans Toggle\ Line\ &Wrap:set\ wrap! Ativar/Desativar\ &quebra\ de\ linhas:set\ wrap! menutrans Toggle\ W&rap\ at\ word:set\ lbr! Ativar/Desativar\ quebra\ na\ &palavra:set\ lbr! -menutrans Toggle\ &expand-tab:set\ et! Ativar/Desativar\ expansão de tabs:set\ et! +menutrans Toggle\ &expand-tab:set\ et! Ativar/Desativar\ expansão\ de\ tabs:set\ et! menutrans Toggle\ &auto-indent:set\ ai! Ativar/Desativar\ &auto-indentação:set\ ai! -menutrans Toggle\ &C-indenting:set\ cin! Ativar/Desativar\ indentação estilo &C:set\ cin! +menutrans Toggle\ &C-indenting:set\ cin! Ativar/Desativar\ indentação\ estilo\ &C:set\ cin! " other options menutrans &Shiftwidth Largura\ da\ &indentação @@ -144,12 +144,12 @@ menutrans &Convert\ to\ HEX:%!xxd Converter\ para\ hexadecimal:%!xxd menutrans Conve&rt\ back:%!xxd\ -r Conver&ter\ de\ volta:%!xxd\ -r " Tools.Spelling menu -menutrans &Spell Check On &Ativar Correção Ortográfica -menutrans &Spell Check Off &Desativar Correção Ortográfica -menutrans To &Next error]s &Próximo Erro]s -menutrans To &Previous Error[s Erro A&nterior[s -menutrans Suggest &Correctionsz= &Sugerir Correçõesz= -menutrans &Repeat correction:spellrepall &Repetir Correção:spellrepall +menutrans &Spell\ Check\ On &Ativar\ Correção\ Ortográfica +menutrans &Spell\ Check\ Off &Desativar\ Correção\ Ortográfica +menutrans To\ &Next\ error]s &Próximo\ Erro]s +menutrans To\ &Previous\ Error[s Erro\ A&nterior[s +menutrans Suggest\ &Correctionsz= &Sugerir\ Correçõesz= +menutrans &Repeat\ correction:spellrepall &Repetir\ Correção:spellrepall menutrans Set\ language\ to\ "en" Inglês menutrans Set\ language\ to\ "en_au" Inglês\ (en_au) @@ -158,7 +158,7 @@ menutrans Set\ language\ to\ "en_gb" Ingl menutrans Set\ language\ to\ "en_nz" Inglês\ (en_nz) menutrans Set\ language\ to\ "en_us" Inglês\ (en_us) -menutrans &Find\ More\ Languages &Buscar mais idiomas +menutrans &Find\ More\ Languages &Buscar\ mais\ idiomas " Tools.Fold Menu menutrans &Enable/Disable\ foldszi &Ativar/Desativar\ dobraszi diff --git a/runtime/lang/menu_pt_pt.vim b/runtime/lang/menu_pt_pt.vim index 783be0b926..c3265c0064 100644 --- a/runtime/lang/menu_pt_pt.vim +++ b/runtime/lang/menu_pt_pt.vim @@ -98,9 +98,9 @@ menutrans Toggle\ Line\ &Numbering:set\ nu! Activar/Desactivar\ &numera menutrans Toggle\ &List\ Mode:set\ list! Activar/Desactivar\ modo\ &list:set\ list! menutrans Toggle\ Line\ &Wrap:set\ wrap! Activar/Desactivar\ &quebra\ de\ linhas:set\ wrap! menutrans Toggle\ W&rap\ at\ word:set\ lbr! Activar/Desactivar\ quebra\ na\ &palavra:set\ lbr! -menutrans Toggle\ &expand-tab:set\ et! Activar/Desactivar\ expansão de tabs:set\ et! +menutrans Toggle\ &expand-tab:set\ et! Activar/Desactivar\ expansão\ de\ tabs:set\ et! menutrans Toggle\ &auto-indent:set\ ai! Activar/Desactivar\ &auto-indentação:set\ ai! -menutrans Toggle\ &C-indenting:set\ cin! Activar/Desactivar\ indentação estilo &C:set\ cin! +menutrans Toggle\ &C-indenting:set\ cin! Activar/Desactivar\ indentação\ estilo\ &C:set\ cin! " other options menutrans &Shiftwidth Largura\ da\ &indentação diff --git a/runtime/lang/menu_sk_sk.iso_8859-2.vim b/runtime/lang/menu_sk_sk.iso_8859-2.vim index 69de4e7b04..02b3f0e152 100644 --- a/runtime/lang/menu_sk_sk.iso_8859-2.vim +++ b/runtime/lang/menu_sk_sk.iso_8859-2.vim @@ -1,6 +1,6 @@ " Menu Translations: Slovak " Translated By: Martin Lacko -" Last Change: 2012 May 01 +" Last Change: 2020 Apr 23 " Quit when menu translations have already been done. if exists("did_menu_trans") @@ -53,12 +53,12 @@ menutrans &Deletex Vy&maza menutrans &Find\.\.\. &Nájs»\.\.\. menutrans Find\ and\ Rep&lace\.\.\. N&ahradi»\.\.\. menutrans Settings\ &Window Mo&¾nosti -menutrans &Global\ Settings &Globálne mo¾nosti +menutrans &Global\ Settings &Globálne\ mo¾nosti menutrans Toggle\ Pattern\ &Highlight:set\ hls! Prepnú»\ paletu\ zvýrazòovania:set\ hls! -menutrans Toggle\ &Ignore-case:set\ ic! Prepnú»\ &ignorovanie veµkosti:set\ ic! +menutrans Toggle\ &Ignore-case:set\ ic! Prepnú»\ &ignorovanie\ veµkosti:set\ ic! menutrans Toggle\ &Showmatch:set\ sm! Prepnú»\ &ukáza»\ zhodu:set\ sm! menutrans &Context\ lines &Kontextové\ riadky -menutrans &Virtual\ Edit &Virtuálne úpravy +menutrans &Virtual\ Edit &Virtuálne\ úpravy menutrans Never Nikdy menutrans Block\ Selection Blokový\ výber menutrans Insert\ mode Re¾im\ vkladania @@ -67,7 +67,7 @@ menutrans Always V menutrans Toggle\ Insert\ &Mode:set\ im! Prepnú»\ re¾i&m\ vkladania:set\ im! menutrans Toggle\ Vi\ C&ompatible:set\ cp! Prepnú»\ vi\ kompatibilitu:set\ cp! menutrans Search\ &Path\.\.\. Cesta\ &hµadania\.\.\. -menutrans Ta&g\ Files\.\.\. Ta&gové súbory\.\.\. +menutrans Ta&g\ Files\.\.\. Ta&gové\ súbory\.\.\. menutrans Toggle\ &Toolbar Prepnú»\ &panel menutrans Toggle\ &Bottom\ Scrollbar Prepnú»\ spodný\ posuvník menutrans Toggle\ &Left\ Scrollbar Prepnú»\ µavý\ posuvník @@ -95,7 +95,7 @@ menutrans &Folding &Vn menutrans &Enable/Disable\ foldszi Zapnú»/Vypnú»\ vnárani&ezi menutrans &View\ Cursor\ Linezv Zobrazi»\ kurzoro&vý\ riadokzv menutrans Vie&w\ Cursor\ Line\ onlyzMzx Zobrazi»\ iba\ kurzorový\ riadokzMzx -menutrans C&lose\ more\ foldszm Zatvori»\ viac \vnorenízm +menutrans C&lose\ more\ foldszm Zatvori»\ viac\ vnorenízm menutrans &Close\ all\ foldszM Zatvor&i»\ v¹etky\ vnoreniazM menutrans O&pen\ more\ foldszr O&tvori»\ viac\ vnorenízr menutrans &Open\ all\ foldszR &Otvori»\ v¹etky\ vnoreniazR @@ -139,7 +139,7 @@ menutrans &Delete Vymaza menutrans &Alternate Zmeni» menutrans &Next Ï&al¹ia menutrans &Previous &Predchádzajúca -menutrans [No File] [®iadny\ súbor] +menutrans [No\ File] [®iadny\ súbor] " Window menu menutrans &Window &Okná @@ -161,7 +161,7 @@ menutrans &Equal\ Size^W= Rovnak menutrans &Max\ Height^W_ &Maximálna\ vý¹ka^W_ menutrans M&in\ Height^W1_ Minimálna\ vý&¹ka^W1_ menutrans Max\ &Width^W\| Maximálna\ ¹írka^W\| -menutrans Min\ Widt&h^W1\| Minimálna ¹irka^W1\| +menutrans Min\ Widt&h^W1\| Minimálna\ ¹irka^W1\| menutrans Rotate\ &Up^WR Rotova&»\ nahor^WR menutrans Rotate\ &Down^Wr Rotova»\ na&dol^Wr menutrans Select\ Fo&nt\.\.\. Vy&bra»\ písmo\.\.\. diff --git a/runtime/lang/menu_sl_si.latin2.vim b/runtime/lang/menu_sl_si.latin2.vim index a810a2a126..cf4b10ba74 100644 --- a/runtime/lang/menu_sl_si.latin2.vim +++ b/runtime/lang/menu_sl_si.latin2.vim @@ -1,7 +1,7 @@ " Menu Translations: Slovenian / Slovensko " Maintainer: Mojca Miklavec " Originally By: Mojca Miklavec -" Last Change: 2016 Oct 17 +" Last Change: 2020 Apr 23 " vim:set foldmethod=marker tabstop=8: " TODO: add/check all '&'s @@ -52,7 +52,7 @@ menutrans Find\ and\ Rep&lace\.\.\. Poi " [-- SETTINGS --] menutrans Settings\ &Window Nastavitve\ \.\.\. -menutrans Startup\ &Settings Zaèetne nastavitve +menutrans Startup\ &Settings Zaèetne\ nastavitve menutrans &Global\ Settings &Globalne\ nastavitve menutrans Toggle\ Pattern\ &Highlight:set\ hls! Vkljuèi/izkljuèi\ poudarjanje\ iskanega\ niza:set\ hls! @@ -92,7 +92,7 @@ menutrans Toggle\ &C-indenting:set\ cin! Vklju " other options menutrans &Shiftwidth ©irina\ zamika\ vrstic -menutrans Soft\ &Tabstop ©irina &tabulatorja +menutrans Soft\ &Tabstop ©irina\ &tabulatorja menutrans Te&xt\ Width\.\.\. ©irina\ besedila\ \.\.\. menutrans &File\ Format\.\.\. Format\ &datoteke\ \.\.\. menutrans C&olor\ Scheme &Barvna\ shema\ \.\.\. diff --git a/runtime/lang/menu_slovak_slovak_republic.1250.vim b/runtime/lang/menu_slovak_slovak_republic.1250.vim index cfc607865c..ce5e15cb32 100644 --- a/runtime/lang/menu_slovak_slovak_republic.1250.vim +++ b/runtime/lang/menu_slovak_slovak_republic.1250.vim @@ -1,6 +1,6 @@ " Menu Translations: Slovak " Translated By: Martin Lacko -" Last Change: 2012 May 01 +" Last Change: 2020 Apr 23 " Quit when menu translations have already been done. if exists("did_menu_trans") @@ -53,12 +53,12 @@ menutrans &Deletex Vy&maza menutrans &Find\.\.\. &Nájs\.\.\. menutrans Find\ and\ Rep&lace\.\.\. N&ahradi\.\.\. menutrans Settings\ &Window Mo&žnosti -menutrans &Global\ Settings &Globálne možnosti +menutrans &Global\ Settings &Globálne\ možnosti menutrans Toggle\ Pattern\ &Highlight:set\ hls! Prepnú\ paletu\ zvýrazòovania:set\ hls! -menutrans Toggle\ &Ignore-case:set\ ic! Prepnú\ &ignorovanie ve¾kosti:set\ ic! +menutrans Toggle\ &Ignore-case:set\ ic! Prepnú\ &ignorovanie\ ve¾kosti:set\ ic! menutrans Toggle\ &Showmatch:set\ sm! Prepnú\ &ukáza\ zhodu:set\ sm! menutrans &Context\ lines &Kontextové\ riadky -menutrans &Virtual\ Edit &Virtuálne úpravy +menutrans &Virtual\ Edit &Virtuálne\ úpravy menutrans Never Nikdy menutrans Block\ Selection Blokový\ výber menutrans Insert\ mode Režim\ vkladania @@ -67,7 +67,7 @@ menutrans Always V menutrans Toggle\ Insert\ &Mode:set\ im! Prepnú\ reži&m\ vkladania:set\ im! menutrans Toggle\ Vi\ C&ompatible:set\ cp! Prepnú\ vi\ kompatibilitu:set\ cp! menutrans Search\ &Path\.\.\. Cesta\ &h¾adania\.\.\. -menutrans Ta&g\ Files\.\.\. Ta&gové súbory\.\.\. +menutrans Ta&g\ Files\.\.\. Ta&gové\ súbory\.\.\. menutrans Toggle\ &Toolbar Prepnú\ &panel menutrans Toggle\ &Bottom\ Scrollbar Prepnú\ spodný\ posuvník menutrans Toggle\ &Left\ Scrollbar Prepnú\ ¾avý\ posuvník @@ -95,7 +95,7 @@ menutrans &Folding &Vn menutrans &Enable/Disable\ foldszi Zapnú/Vypnú\ vnárani&ezi menutrans &View\ Cursor\ Linezv Zobrazi\ kurzoro&vý\ riadokzv menutrans Vie&w\ Cursor\ Line\ onlyzMzx Zobrazi\ iba\ kurzorový\ riadokzMzx -menutrans C&lose\ more\ foldszm Zatvori\ viac \vnorenízm +menutrans C&lose\ more\ foldszm Zatvori\ viac\ vnorenízm menutrans &Close\ all\ foldszM Zatvor&i\ všetky\ vnoreniazM menutrans O&pen\ more\ foldszr O&tvori\ viac\ vnorenízr menutrans &Open\ all\ foldszR &Otvori\ všetky\ vnoreniazR @@ -139,7 +139,7 @@ menutrans &Delete Vymaza menutrans &Alternate Zmeni menutrans &Next Ï&alšia menutrans &Previous &Predchádzajúca -menutrans [No File] [Žiadny\ súbor] +menutrans [No\ File] [Žiadny\ súbor] " Window menu menutrans &Window &Okná @@ -161,7 +161,7 @@ menutrans &Equal\ Size^W= Rovnak menutrans &Max\ Height^W_ &Maximálna\ výška^W_ menutrans M&in\ Height^W1_ Minimálna\ vý&ška^W1_ menutrans Max\ &Width^W\| Maximálna\ šírka^W\| -menutrans Min\ Widt&h^W1\| Minimálna širka^W1\| +menutrans Min\ Widt&h^W1\| Minimálna\ širka^W1\| menutrans Rotate\ &Up^WR Rotova&\ nahor^WR menutrans Rotate\ &Down^Wr Rotova\ na&dol^Wr menutrans Select\ Fo&nt\.\.\. Vy&bra\ písmo\.\.\. diff --git a/runtime/lang/menu_sv_se.latin1.vim b/runtime/lang/menu_sv_se.latin1.vim index 2e37485306..53e1f40790 100644 --- a/runtime/lang/menu_sv_se.latin1.vim +++ b/runtime/lang/menu_sv_se.latin1.vim @@ -1,6 +1,6 @@ " Menu Translations: Swedish " Maintainer: Johan Svedberg -" Last Change: 2012 May 01 +" Last Change: 2020 Apr 22 " Quit when menu translations have already been done. if exists("did_menu_trans") @@ -51,7 +51,7 @@ menutrans &Redo^R &G menutrans Rep&eat\. &Repetera\. menutrans Cu&t"+x Klipp\ &ut"+x menutrans &Copy"+y &Kopiera"+y -menutrans &Paste"+gP Klistra &in"+gP +menutrans &Paste"+gP Klistra\ &in"+gP menutrans Put\ &Before[p Sätt\ in\ &före[p menutrans Put\ &After]p Sätt\ in\ &efter]p menutrans &Select\ AllggVG &Markera\ alltggVG diff --git a/runtime/lang/menu_tr_tr.cp1254.vim b/runtime/lang/menu_tr_tr.cp1254.vim index 687e2ac257..d1c3d973fd 100644 --- a/runtime/lang/menu_tr_tr.cp1254.vim +++ b/runtime/lang/menu_tr_tr.cp1254.vim @@ -11,19 +11,19 @@ set cpo&vim scriptencoding cp1254 " Top -menutrans &File &Dosya -menutrans &Edit Dü&zen +menutrans &File &Dosya +menutrans &Edit Dü&zen menutrans &Tools &Araçlar menutrans &Syntax &Sözdizim menutrans &Buffers A&rabellekler menutrans &Window &Pencere -menutrans &Help &Yardým +menutrans &Help &Yardým " Help menu menutrans &Overview &Genel\ Bakýþ -menutrans &User\ Manual &Kullaným\ Kýlavuzu +menutrans &User\ Manual &Kullaným\ Kýlavuzu menutrans &How-To\ Links &Nasýl\ Yapýlýr? -menutrans &Find\.\.\. &Bul\.\.\. +menutrans &Find\.\.\. &Bul\.\.\. "-------------------- menutrans &Credits &Teþekkürler menutrans Co&pying &Daðýtým @@ -37,38 +37,38 @@ menutrans &About &Hakk menutrans &Open\.\.\.:e &Aç\.\.\.:e menutrans Sp&lit-Open\.\.\.:sp &Yeni\ Bölümde\ Aç\.\.\.:sp menutrans Open\ Tab\.\.\.:tabnew S&ekme\ Aç\.\.\.:tabnew -menutrans &New:enew Yeni\ &Sekme:enew +menutrans &New:enew Yeni\ &Sekme:enew menutrans &Close:close Ka&pat:close "-------------------- menutrans &Save:w Kayde&t:w -menutrans Save\ &As\.\.\.:sav &Farklý Kaydet\.\.\.:sav +menutrans Save\ &As\.\.\.:sav &Farklý\ Kaydet\.\.\.:sav "-------------------- menutrans Split\ &Diff\ With\.\.\. Ka&rþýlaþtýr\.\.\. -menutrans Split\ Patched\ &By\.\.\. Ya&malar\ Dahil\ Karþýlaþtýr\.\.\. +menutrans Split\ Patched\ &By\.\.\. Ya&ma\ Ýle\ Karþýlaþtýr\.\.\. "-------------------- menutrans &Print Ya&zdýr -menutrans Sa&ve-Exit:wqa Kaydet\ &ve Çýk:wqa +menutrans Sa&ve-Exit:wqa Kaydet\ &ve\ Çýk:wqa menutrans E&xit:qa Çý&k:qa " Edit menu -menutrans &Undou &Geri\ Alu -menutrans &Redo^R &Yinele^R -menutrans Rep&eat\. Son\ Komutu\ Y&inele\. +menutrans &Undou &Geri\ Alu +menutrans &Redo^R &Yinele^R +menutrans Rep&eat\. Son\ Komutu\ Y&inele\. "-------------------- -menutrans Cu&t"+x &Kes"+x -menutrans &Copy"+y K&opyala"+y -menutrans &Paste"+gP Ya&pýþtýr"+gP -menutrans Put\ &Before[p Ö&nüne Koy[p -menutrans Put\ &After]p A&rkasýna Koy]p -menutrans &Deletex Si&lx +menutrans Cu&t"+x &Kes"+x +menutrans &Copy"+y K&opyala"+y +menutrans &Paste"+gP Ya&pýþtýr"+gP +menutrans Put\ &Before[p Ö&nüne\ Koy[p +menutrans Put\ &After]p A&rkasýna\ Koy]p +menutrans &Deletex Si&lx menutrans &Select\ AllggVG Tü&münü\ SeçggVG "-------------------- " Athena GUI only -menutrans &Find/ &Bul/ -menutrans Find\ and\ Rep&lace:%s Bul\ &ve\ Deðiþtir:%s +menutrans &Find/ &Bul/ +menutrans Find\ and\ Rep&lace:%s Bul\ &ve\ Deðiþtir:%s " End Athena GUI only -menutrans &Find\.\.\./ &Bul\.\.\./ -menutrans Find\ and\ Rep&lace\.\.\. Bul\ ve\ &Deðiþtir\.\.\. +menutrans &Find\.\.\./ &Bul\.\.\./ +menutrans Find\ and\ Rep&lace\.\.\. Bul\ ve\ &Deðiþtir\.\.\. menutrans Find\ and\ Rep&lace\.\.\.:%s Bul\ ve\ &Deðiþtir\.\.\.:%s menutrans Find\ and\ Rep&lace\.\.\.:s Bul\ ve\ &Deðiþtir\.\.\.:s "-------------------- @@ -78,11 +78,11 @@ menutrans &Global\ Settings Ge&nel\ Ayarlar menutrans F&ile\ Settings &Dosya\ Ayarlarý menutrans C&olor\ Scheme &Renk\ Düzeni menutrans &Keymap Düðme\ &Eþlem -menutrans Select\ Fo&nt\.\.\. Ya&zýtipi Seç\.\.\. +menutrans Select\ Fo&nt\.\.\. Ya&zýtipi\ Seç\.\.\. ">>>----------------- Edit/Global settings -menutrans Toggle\ Pattern\ &Highlight:set\ hls! Dizgi\ &Vurgulamasýný\ Aç/Kapat:set\ hls! -menutrans Toggle\ &Ignoring\ Case:set\ ic! BÜYÜK/küçük\ Harf\ &Duyarlý\ Aç/Kapat:set\ ic! +menutrans Toggle\ Pattern\ &Highlight:set\ hls! Dizgi\ &Vurgulamasýný\ Aç/Kapat:set\ hls! +menutrans Toggle\ &Ignoring\ Case:set\ ic! BÜYÜK/küçük\ Harf\ &Duyarlý\ Aç/Kapat:set\ ic! menutrans Toggle\ &Showing\ Matched\ Pairs:set\ sm! Eþ&leþen\ Ýkilileri\ Aç/Kapat:set\ sm! menutrans &Context\ Lines Ý&mleçle\ Oynayan\ Satýrlar menutrans &Virtual\ Edit &Sanal\ Düzenleme @@ -97,11 +97,11 @@ menutrans Toggle\ &Left\ Scrollbar &Sol\ Kayd menutrans Toggle\ &Right\ Scrollbar S&að\ Kaydýrma\ Çubuðunu\ Aç/Kapat ">>>->>>------------- Edit/Global settings/Virtual edit -menutrans Never Kapalý +menutrans Never Kapalý menutrans Block\ Selection Blok\ Seçimi menutrans Insert\ Mode Ekleme\ Kipi menutrans Block\ and\ Insert Blok\ Seçiminde\ ve\ Ekleme\ Kipinde -menutrans Always Her\ Zaman\ Açýk +menutrans Always Her\ Zaman\ Açýk ">>>----------------- Edit/File settings menutrans Toggle\ Line\ &Numbering:set\ nu! &Satýr\ Numaralandýrmayý\ Aç/Kapat:set\ nu! menutrans Toggle\ Relati&ve\ Line\ Numbering:set\ rnu! &Göreceli\ Satýr\ Numaralandýrmayý\ Aç/Kapat:set\ nru! @@ -124,10 +124,10 @@ menutrans Build\ &Tags\ File &Etiket\ Dosyas "------------------- menutrans &Folding &Kývýrmalar menutrans &Spelling &Yazým\ Denetimi -menutrans &Diff &Ayrýmlar\ (diff) +menutrans &Diff K&arþýlaþtýrma\ (diff) "------------------- menutrans &Make:make &Derle:make -menutrans &List\ Errors:cl &Hatalarý\ Listele:cl +menutrans &List\ Errors:cl &Hatalarý\ Listele:cl menutrans L&ist\ Messages:cl! Ý&letileri\ Listele:cl! menutrans &Next\ Error:cn Bir\ &Sonraki\ Hata:cn menutrans &Previous\ Error:cp Bir\ Ö&nceki\ Hata:cp @@ -137,8 +137,8 @@ menutrans Error\ &Window Hatalar\ &Penceresi menutrans Se&t\ Compiler De&rleyici\ Seç menutrans Show\ Compiler\ Se&ttings\ in\ Menu Derleyici\ Ayarlarýný\ Menüde\ &Göster "------------------- -menutrans &Convert\ to\ HEX:%!xxd HEX'e\ Dö&nüþtür:%!xxd -menutrans Conve&rt\ Back:%!xxd\ -r HEX'&ten\ Dönüþtür:%!xxd\ -r +menutrans &Convert\ to\ HEX:%!xxd HEX'e\ Dö&nüþtür:%!xxd +menutrans Conve&rt\ Back:%!xxd\ -r HEX'&ten\ Dönüþtür:%!xxd\ -r ">>>---------------- Tools/Spelling menutrans &Spell\ Check\ On Yazým\ Denetimini\ &Aç menutrans Spell\ Check\ &Off Yazým\ Denetimini\ &Kapat @@ -191,7 +191,7 @@ menutrans &Open:copen &A " Syntax menu menutrans &Show\ File\ Types\ in\ Menu Dosya\ Türlerini\ Menüde\ &Göster menutrans Set\ '&syntax'\ only Yalnýzca\ 'syntax'\ &Ayarla -menutrans Set\ '&filetype'\ too 'filetype'\ Ýçin\ &de\ Ayarla +menutrans Set\ '&filetype'\ too 'filetype'\ Ýçin\ &de\ Ayarla menutrans &Off &Kapat menutrans &Manual &El\ Ýle menutrans A&utomatic &Otomatik @@ -204,7 +204,7 @@ menutrans &Convert\ to\ HTML &HTML'ye\ D menutrans &Refresh\ menu &Menüyü\ Güncelle menutrans Delete &Sil menutrans &Alternate Ö&teki -menutrans &Next So&nraki +menutrans &Next So&nraki menutrans &Previous Ön&ceki menutrans [No\ File] [Dosya\ Yok] @@ -235,16 +235,16 @@ menutrans &Left\ Side^WH So&la^WH menutrans &Right\ Side^WL &Saða^WL " The popup menu -menutrans &Undo &Geri\ Al +menutrans &Undo &Geri\ Al menutrans Cu&t &Kes -menutrans &Copy K&opyala +menutrans &Copy K&opyala menutrans &Paste &Yapýþtýr menutrans &Delete &Sil menutrans Select\ Blockwise &Blok\ Biçiminde\ Seç -menutrans Select\ &Word Sö&zcük\ Seç +menutrans Select\ &Word Sö&zcük\ Seç menutrans Select\ &Sentence &Tümce\ Seç menutrans Select\ Pa&ragraph &Paragraf\ Seç -menutrans Select\ &Line S&atýr\ Seç +menutrans Select\ &Line S&atýr\ Seç menutrans Select\ &Block Bl&ok\ Seç menutrans Select\ &All Tümü&nü\ Seç diff --git a/runtime/lang/menu_tr_tr.iso_8859-9.vim b/runtime/lang/menu_tr_tr.iso_8859-9.vim index 3e01c0c8aa..0065bc5236 100644 --- a/runtime/lang/menu_tr_tr.iso_8859-9.vim +++ b/runtime/lang/menu_tr_tr.iso_8859-9.vim @@ -11,19 +11,19 @@ set cpo&vim scriptencoding iso-8859-9 " Top -menutrans &File &Dosya -menutrans &Edit Dü&zen +menutrans &File &Dosya +menutrans &Edit Dü&zen menutrans &Tools &Araçlar menutrans &Syntax &Sözdizim menutrans &Buffers A&rabellekler menutrans &Window &Pencere -menutrans &Help &Yardým +menutrans &Help &Yardým " Help menu menutrans &Overview &Genel\ Bakýþ -menutrans &User\ Manual &Kullaným\ Kýlavuzu +menutrans &User\ Manual &Kullaným\ Kýlavuzu menutrans &How-To\ Links &Nasýl\ Yapýlýr? -menutrans &Find\.\.\. &Bul\.\.\. +menutrans &Find\.\.\. &Bul\.\.\. "-------------------- menutrans &Credits &Teþekkürler menutrans Co&pying &Daðýtým @@ -37,38 +37,38 @@ menutrans &About &Hakk menutrans &Open\.\.\.:e &Aç\.\.\.:e menutrans Sp&lit-Open\.\.\.:sp &Yeni\ Bölümde\ Aç\.\.\.:sp menutrans Open\ Tab\.\.\.:tabnew S&ekme\ Aç\.\.\.:tabnew -menutrans &New:enew Yeni\ &Sekme:enew +menutrans &New:enew Yeni\ &Sekme:enew menutrans &Close:close Ka&pat:close "-------------------- menutrans &Save:w Kayde&t:w -menutrans Save\ &As\.\.\.:sav &Farklý Kaydet\.\.\.:sav +menutrans Save\ &As\.\.\.:sav &Farklý\ Kaydet\.\.\.:sav "-------------------- menutrans Split\ &Diff\ With\.\.\. Ka&rþýlaþtýr\.\.\. -menutrans Split\ Patched\ &By\.\.\. Ya&malar\ Dahil\ Karþýlaþtýr\.\.\. +menutrans Split\ Patched\ &By\.\.\. Ya&ma\ Ýle\ Karþýlaþtýr\.\.\. "-------------------- menutrans &Print Ya&zdýr -menutrans Sa&ve-Exit:wqa Kaydet\ &ve Çýk:wqa +menutrans Sa&ve-Exit:wqa Kaydet\ &ve\ Çýk:wqa menutrans E&xit:qa Çý&k:qa " Edit menu -menutrans &Undou &Geri\ Alu -menutrans &Redo^R &Yinele^R -menutrans Rep&eat\. Son\ Komutu\ Y&inele\. +menutrans &Undou &Geri\ Alu +menutrans &Redo^R &Yinele^R +menutrans Rep&eat\. Son\ Komutu\ Y&inele\. "-------------------- -menutrans Cu&t"+x &Kes"+x -menutrans &Copy"+y K&opyala"+y -menutrans &Paste"+gP Ya&pýþtýr"+gP -menutrans Put\ &Before[p Ö&nüne Koy[p -menutrans Put\ &After]p A&rkasýna Koy]p -menutrans &Deletex Si&lx +menutrans Cu&t"+x &Kes"+x +menutrans &Copy"+y K&opyala"+y +menutrans &Paste"+gP Ya&pýþtýr"+gP +menutrans Put\ &Before[p Ö&nüne\ Koy[p +menutrans Put\ &After]p A&rkasýna\ Koy]p +menutrans &Deletex Si&lx menutrans &Select\ AllggVG Tü&münü\ SeçggVG "-------------------- " Athena GUI only -menutrans &Find/ &Bul/ -menutrans Find\ and\ Rep&lace:%s Bul\ &ve\ Deðiþtir:%s +menutrans &Find/ &Bul/ +menutrans Find\ and\ Rep&lace:%s Bul\ &ve\ Deðiþtir:%s " End Athena GUI only -menutrans &Find\.\.\./ &Bul\.\.\./ -menutrans Find\ and\ Rep&lace\.\.\. Bul\ ve\ &Deðiþtir\.\.\. +menutrans &Find\.\.\./ &Bul\.\.\./ +menutrans Find\ and\ Rep&lace\.\.\. Bul\ ve\ &Deðiþtir\.\.\. menutrans Find\ and\ Rep&lace\.\.\.:%s Bul\ ve\ &Deðiþtir\.\.\.:%s menutrans Find\ and\ Rep&lace\.\.\.:s Bul\ ve\ &Deðiþtir\.\.\.:s "-------------------- @@ -78,11 +78,11 @@ menutrans &Global\ Settings Ge&nel\ Ayarlar menutrans F&ile\ Settings &Dosya\ Ayarlarý menutrans C&olor\ Scheme &Renk\ Düzeni menutrans &Keymap Düðme\ &Eþlem -menutrans Select\ Fo&nt\.\.\. Ya&zýtipi Seç\.\.\. +menutrans Select\ Fo&nt\.\.\. Ya&zýtipi\ Seç\.\.\. ">>>----------------- Edit/Global settings -menutrans Toggle\ Pattern\ &Highlight:set\ hls! Dizgi\ &Vurgulamasýný\ Aç/Kapat:set\ hls! -menutrans Toggle\ &Ignoring\ Case:set\ ic! BÜYÜK/küçük\ Harf\ &Duyarlý\ Aç/Kapat:set\ ic! +menutrans Toggle\ Pattern\ &Highlight:set\ hls! Dizgi\ &Vurgulamasýný\ Aç/Kapat:set\ hls! +menutrans Toggle\ &Ignoring\ Case:set\ ic! BÜYÜK/küçük\ Harf\ &Duyarlý\ Aç/Kapat:set\ ic! menutrans Toggle\ &Showing\ Matched\ Pairs:set\ sm! Eþ&leþen\ Ýkilileri\ Aç/Kapat:set\ sm! menutrans &Context\ Lines Ý&mleçle\ Oynayan\ Satýrlar menutrans &Virtual\ Edit &Sanal\ Düzenleme @@ -97,11 +97,11 @@ menutrans Toggle\ &Left\ Scrollbar &Sol\ Kayd menutrans Toggle\ &Right\ Scrollbar S&að\ Kaydýrma\ Çubuðunu\ Aç/Kapat ">>>->>>------------- Edit/Global settings/Virtual edit -menutrans Never Kapalý +menutrans Never Kapalý menutrans Block\ Selection Blok\ Seçimi menutrans Insert\ Mode Ekleme\ Kipi menutrans Block\ and\ Insert Blok\ Seçiminde\ ve\ Ekleme\ Kipinde -menutrans Always Her\ Zaman\ Açýk +menutrans Always Her\ Zaman\ Açýk ">>>----------------- Edit/File settings menutrans Toggle\ Line\ &Numbering:set\ nu! &Satýr\ Numaralandýrmayý\ Aç/Kapat:set\ nu! menutrans Toggle\ Relati&ve\ Line\ Numbering:set\ rnu! &Göreceli\ Satýr\ Numaralandýrmayý\ Aç/Kapat:set\ nru! @@ -124,10 +124,10 @@ menutrans Build\ &Tags\ File &Etiket\ Dosyas "------------------- menutrans &Folding &Kývýrmalar menutrans &Spelling &Yazým\ Denetimi -menutrans &Diff &Ayrýmlar\ (diff) +menutrans &Diff K&arþýlaþtýrma\ (diff) "------------------- menutrans &Make:make &Derle:make -menutrans &List\ Errors:cl &Hatalarý\ Listele:cl +menutrans &List\ Errors:cl &Hatalarý\ Listele:cl menutrans L&ist\ Messages:cl! Ý&letileri\ Listele:cl! menutrans &Next\ Error:cn Bir\ &Sonraki\ Hata:cn menutrans &Previous\ Error:cp Bir\ Ö&nceki\ Hata:cp @@ -137,8 +137,8 @@ menutrans Error\ &Window Hatalar\ &Penceresi menutrans Se&t\ Compiler De&rleyici\ Seç menutrans Show\ Compiler\ Se&ttings\ in\ Menu Derleyici\ Ayarlarýný\ Menüde\ &Göster "------------------- -menutrans &Convert\ to\ HEX:%!xxd HEX'e\ Dö&nüþtür:%!xxd -menutrans Conve&rt\ Back:%!xxd\ -r HEX'&ten\ Dönüþtür:%!xxd\ -r +menutrans &Convert\ to\ HEX:%!xxd HEX'e\ Dö&nüþtür:%!xxd +menutrans Conve&rt\ Back:%!xxd\ -r HEX'&ten\ Dönüþtür:%!xxd\ -r ">>>---------------- Tools/Spelling menutrans &Spell\ Check\ On Yazým\ Denetimini\ &Aç menutrans Spell\ Check\ &Off Yazým\ Denetimini\ &Kapat @@ -191,7 +191,7 @@ menutrans &Open:copen &A " Syntax menu menutrans &Show\ File\ Types\ in\ Menu Dosya\ Türlerini\ Menüde\ &Göster menutrans Set\ '&syntax'\ only Yalnýzca\ 'syntax'\ &Ayarla -menutrans Set\ '&filetype'\ too 'filetype'\ Ýçin\ &de\ Ayarla +menutrans Set\ '&filetype'\ too 'filetype'\ Ýçin\ &de\ Ayarla menutrans &Off &Kapat menutrans &Manual &El\ Ýle menutrans A&utomatic &Otomatik @@ -204,7 +204,7 @@ menutrans &Convert\ to\ HTML &HTML'ye\ D menutrans &Refresh\ menu &Menüyü\ Güncelle menutrans Delete &Sil menutrans &Alternate Ö&teki -menutrans &Next So&nraki +menutrans &Next So&nraki menutrans &Previous Ön&ceki menutrans [No\ File] [Dosya\ Yok] @@ -235,16 +235,16 @@ menutrans &Left\ Side^WH So&la^WH menutrans &Right\ Side^WL &Saða^WL " The popup menu -menutrans &Undo &Geri\ Al +menutrans &Undo &Geri\ Al menutrans Cu&t &Kes -menutrans &Copy K&opyala +menutrans &Copy K&opyala menutrans &Paste &Yapýþtýr menutrans &Delete &Sil menutrans Select\ Blockwise &Blok\ Biçiminde\ Seç -menutrans Select\ &Word Sö&zcük\ Seç +menutrans Select\ &Word Sö&zcük\ Seç menutrans Select\ &Sentence &Tümce\ Seç menutrans Select\ Pa&ragraph &Paragraf\ Seç -menutrans Select\ &Line S&atýr\ Seç +menutrans Select\ &Line S&atýr\ Seç menutrans Select\ &Block Bl&ok\ Seç menutrans Select\ &All Tümü&nü\ Seç diff --git a/runtime/lang/menu_tr_tr.utf-8.vim b/runtime/lang/menu_tr_tr.utf-8.vim index a828acfc4f..02a095643c 100644 --- a/runtime/lang/menu_tr_tr.utf-8.vim +++ b/runtime/lang/menu_tr_tr.utf-8.vim @@ -11,19 +11,19 @@ set cpo&vim scriptencoding utf-8 " Top -menutrans &File &Dosya -menutrans &Edit Dü&zen +menutrans &File &Dosya +menutrans &Edit Dü&zen menutrans &Tools &Araçlar menutrans &Syntax &Sözdizim menutrans &Buffers A&rabellekler menutrans &Window &Pencere -menutrans &Help &Yardım +menutrans &Help &Yardım " Help menu menutrans &Overview &Genel\ Bakış -menutrans &User\ Manual &Kullanım\ Kılavuzu +menutrans &User\ Manual &Kullanım\ Kılavuzu menutrans &How-To\ Links &Nasıl\ Yapılır? -menutrans &Find\.\.\. &Bul\.\.\. +menutrans &Find\.\.\. &Bul\.\.\. "-------------------- menutrans &Credits &TeÅŸekkürler menutrans Co&pying &Dağıtım @@ -37,38 +37,38 @@ menutrans &About &Hakkında menutrans &Open\.\.\.:e &Aç\.\.\.:e menutrans Sp&lit-Open\.\.\.:sp &Yeni\ Bölümde\ Aç\.\.\.:sp menutrans Open\ Tab\.\.\.:tabnew S&ekme\ Aç\.\.\.:tabnew -menutrans &New:enew Yeni\ &Sekme:enew +menutrans &New:enew Yeni\ &Sekme:enew menutrans &Close:close Ka&pat:close "-------------------- menutrans &Save:w Kayde&t:w -menutrans Save\ &As\.\.\.:sav &Farklı Kaydet\.\.\.:sav +menutrans Save\ &As\.\.\.:sav &Farklı\ Kaydet\.\.\.:sav "-------------------- menutrans Split\ &Diff\ With\.\.\. Ka&rşılaÅŸtır\.\.\. -menutrans Split\ Patched\ &By\.\.\. Ya&malar\ Dahil\ KarşılaÅŸtır\.\.\. +menutrans Split\ Patched\ &By\.\.\. Ya&ma\ İle\ KarşılaÅŸtır\.\.\. "-------------------- menutrans &Print Ya&zdır -menutrans Sa&ve-Exit:wqa Kaydet\ &ve Çık:wqa +menutrans Sa&ve-Exit:wqa Kaydet\ &ve\ Çık:wqa menutrans E&xit:qa Çı&k:qa " Edit menu -menutrans &Undou &Geri\ Alu -menutrans &Redo^R &Yinele^R -menutrans Rep&eat\. Son\ Komutu\ Y&inele\. +menutrans &Undou &Geri\ Alu +menutrans &Redo^R &Yinele^R +menutrans Rep&eat\. Son\ Komutu\ Y&inele\. "-------------------- -menutrans Cu&t"+x &Kes"+x -menutrans &Copy"+y K&opyala"+y -menutrans &Paste"+gP Ya&pıştır"+gP -menutrans Put\ &Before[p Ö&nüne Koy[p -menutrans Put\ &After]p A&rkasına Koy]p -menutrans &Deletex Si&lx +menutrans Cu&t"+x &Kes"+x +menutrans &Copy"+y K&opyala"+y +menutrans &Paste"+gP Ya&pıştır"+gP +menutrans Put\ &Before[p Ö&nüne\ Koy[p +menutrans Put\ &After]p A&rkasına\ Koy]p +menutrans &Deletex Si&lx menutrans &Select\ AllggVG Tü&münü\ SeçggVG "-------------------- " Athena GUI only -menutrans &Find/ &Bul/ -menutrans Find\ and\ Rep&lace:%s Bul\ &ve\ DeÄŸiÅŸtir:%s +menutrans &Find/ &Bul/ +menutrans Find\ and\ Rep&lace:%s Bul\ &ve\ DeÄŸiÅŸtir:%s " End Athena GUI only -menutrans &Find\.\.\./ &Bul\.\.\./ -menutrans Find\ and\ Rep&lace\.\.\. Bul\ ve\ &DeÄŸiÅŸtir\.\.\. +menutrans &Find\.\.\./ &Bul\.\.\./ +menutrans Find\ and\ Rep&lace\.\.\. Bul\ ve\ &DeÄŸiÅŸtir\.\.\. menutrans Find\ and\ Rep&lace\.\.\.:%s Bul\ ve\ &DeÄŸiÅŸtir\.\.\.:%s menutrans Find\ and\ Rep&lace\.\.\.:s Bul\ ve\ &DeÄŸiÅŸtir\.\.\.:s "-------------------- @@ -78,11 +78,11 @@ menutrans &Global\ Settings Ge&nel\ Ayarlar menutrans F&ile\ Settings &Dosya\ Ayarları menutrans C&olor\ Scheme &Renk\ Düzeni menutrans &Keymap Düğme\ &EÅŸlem -menutrans Select\ Fo&nt\.\.\. Ya&zıtipi Seç\.\.\. +menutrans Select\ Fo&nt\.\.\. Ya&zıtipi\ Seç\.\.\. ">>>----------------- Edit/Global settings -menutrans Toggle\ Pattern\ &Highlight:set\ hls! Dizgi\ &Vurgulamasını\ Aç/Kapat:set\ hls! -menutrans Toggle\ &Ignoring\ Case:set\ ic! BÜYÜK/küçük\ Harf\ &Duyarlı\ Aç/Kapat:set\ ic! +menutrans Toggle\ Pattern\ &Highlight:set\ hls! Dizgi\ &Vurgulamasını\ Aç/Kapat:set\ hls! +menutrans Toggle\ &Ignoring\ Case:set\ ic! BÜYÜK/küçük\ Harf\ &Duyarlı\ Aç/Kapat:set\ ic! menutrans Toggle\ &Showing\ Matched\ Pairs:set\ sm! EÅŸ&leÅŸen\ İkilileri\ Aç/Kapat:set\ sm! menutrans &Context\ Lines İ&mleçle\ Oynayan\ Satırlar menutrans &Virtual\ Edit &Sanal\ Düzenleme @@ -97,11 +97,11 @@ menutrans Toggle\ &Left\ Scrollbar &Sol\ Kaydırma\ ÇubuÄŸunu\ Aç/Kapat menutrans Toggle\ &Right\ Scrollbar S&aÄŸ\ Kaydırma\ ÇubuÄŸunu\ Aç/Kapat ">>>->>>------------- Edit/Global settings/Virtual edit -menutrans Never Kapalı +menutrans Never Kapalı menutrans Block\ Selection Blok\ Seçimi menutrans Insert\ Mode Ekleme\ Kipi menutrans Block\ and\ Insert Blok\ Seçiminde\ ve\ Ekleme\ Kipinde -menutrans Always Her\ Zaman\ Açık +menutrans Always Her\ Zaman\ Açık ">>>----------------- Edit/File settings menutrans Toggle\ Line\ &Numbering:set\ nu! &Satır\ Numaralandırmayı\ Aç/Kapat:set\ nu! menutrans Toggle\ Relati&ve\ Line\ Numbering:set\ rnu! &Göreceli\ Satır\ Numaralandırmayı\ Aç/Kapat:set\ nru! @@ -124,10 +124,10 @@ menutrans Build\ &Tags\ File &Etiket\ Dosyası\ OluÅŸtur "------------------- menutrans &Folding &Kıvırmalar menutrans &Spelling &Yazım\ Denetimi -menutrans &Diff &Ayrımlar\ (diff) +menutrans &Diff K&arşılaÅŸtırma\ (diff) "------------------- menutrans &Make:make &Derle:make -menutrans &List\ Errors:cl &Hataları\ Listele:cl +menutrans &List\ Errors:cl &Hataları\ Listele:cl menutrans L&ist\ Messages:cl! İ&letileri\ Listele:cl! menutrans &Next\ Error:cn Bir\ &Sonraki\ Hata:cn menutrans &Previous\ Error:cp Bir\ Ö&nceki\ Hata:cp @@ -137,8 +137,8 @@ menutrans Error\ &Window Hatalar\ &Penceresi menutrans Se&t\ Compiler De&rleyici\ Seç menutrans Show\ Compiler\ Se&ttings\ in\ Menu Derleyici\ Ayarlarını\ Menüde\ &Göster "------------------- -menutrans &Convert\ to\ HEX:%!xxd HEX'e\ Dö&nüştür:%!xxd -menutrans Conve&rt\ Back:%!xxd\ -r HEX'&ten\ Dönüştür:%!xxd\ -r +menutrans &Convert\ to\ HEX:%!xxd HEX'e\ Dö&nüştür:%!xxd +menutrans Conve&rt\ Back:%!xxd\ -r HEX'&ten\ Dönüştür:%!xxd\ -r ">>>---------------- Tools/Spelling menutrans &Spell\ Check\ On Yazım\ Denetimini\ &Aç menutrans Spell\ Check\ &Off Yazım\ Denetimini\ &Kapat @@ -191,7 +191,7 @@ menutrans &Open:copen &Aç:copen " Syntax menu menutrans &Show\ File\ Types\ in\ Menu Dosya\ Türlerini\ Menüde\ &Göster menutrans Set\ '&syntax'\ only Yalnızca\ 'syntax'\ &Ayarla -menutrans Set\ '&filetype'\ too 'filetype'\ İçin\ &de\ Ayarla +menutrans Set\ '&filetype'\ too 'filetype'\ İçin\ &de\ Ayarla menutrans &Off &Kapat menutrans &Manual &El\ İle menutrans A&utomatic &Otomatik @@ -204,7 +204,7 @@ menutrans &Convert\ to\ HTML &HTML'ye\ Dönüştür menutrans &Refresh\ menu &Menüyü\ Güncelle menutrans Delete &Sil menutrans &Alternate Ö&teki -menutrans &Next So&nraki +menutrans &Next So&nraki menutrans &Previous Ön&ceki menutrans [No\ File] [Dosya\ Yok] @@ -235,16 +235,16 @@ menutrans &Left\ Side^WH So&la^WH menutrans &Right\ Side^WL &SaÄŸa^WL " The popup menu -menutrans &Undo &Geri\ Al +menutrans &Undo &Geri\ Al menutrans Cu&t &Kes -menutrans &Copy K&opyala +menutrans &Copy K&opyala menutrans &Paste &Yapıştır menutrans &Delete &Sil menutrans Select\ Blockwise &Blok\ Biçiminde\ Seç -menutrans Select\ &Word Sö&zcük\ Seç +menutrans Select\ &Word Sö&zcük\ Seç menutrans Select\ &Sentence &Tümce\ Seç menutrans Select\ Pa&ragraph &Paragraf\ Seç -menutrans Select\ &Line S&atır\ Seç +menutrans Select\ &Line S&atır\ Seç menutrans Select\ &Block Bl&ok\ Seç menutrans Select\ &All Tümü&nü\ Seç @@ -305,4 +305,4 @@ let g:menutrans_fileformat_dialog = "Dosya biçimi seçin" let g:menutrans_fileformat_choices = "&Unix\n&Dos\n&Mac\nİ&ptal" let menutrans_no_file = "[Dosya Yok]" let &cpo = s:keepcpo -unlet s:keepcpo \ No newline at end of file +unlet s:keepcpo diff --git a/runtime/lang/menu_vi_vn.vim b/runtime/lang/menu_vi_vn.vim index 9fbd2c6d5c..563ffa2485 100644 --- a/runtime/lang/menu_vi_vn.vim +++ b/runtime/lang/menu_vi_vn.vim @@ -58,7 +58,7 @@ menutrans Split\ &Diff\ with\.\.\. &So\ sánh\ vá»›i\.\.\. menutrans Split\ Patched\ &By\.\.\. So\ sánh\ đã\ vá\ lá»—i\ &bởi\.\.\. "-------------------- menutrans &Print In\ &ra -menutrans Sa&ve-Exit:wqa Ghi\ nhá»›\ rồi\ th&oát :wqa +menutrans Sa&ve-Exit:wqa Ghi\ nhá»›\ rồi\ th&oát\ :wqa menutrans E&xit:qa &Thoát:qa " " @@ -87,7 +87,7 @@ menutrans C&olor\ Scheme Phối\ hợp\ màu\ &sắc menutrans &Keymap SÆ¡\ đồ\ &bàn\ phím menutrans Select\ Fo&nt\.\.\. Chá»n\ &phông\ chữ\.\.\. ">>>----------------- Edit/Global settings -menutrans Toggle\ Pattern\ &Highlight:set\ hls! &Chiếu\ sáng\ từ\ tìm\ thấy :set\ hls! +menutrans Toggle\ Pattern\ &Highlight:set\ hls! &Chiếu\ sáng\ từ\ tìm\ thấy\ :set\ hls! menutrans Toggle\ &Ignore-case:set\ ic! &Không\ tính\ đến\ kiểu\ chữ:set\ ic! menutrans Toggle\ &Showmatch:set\ sm! Cho\ &biết\ phần\ tá»­\ có\ cặp:set\ sm! menutrans &Context\ lines Số\ &dòng\ quanh\ con\ trá» @@ -149,7 +149,7 @@ menutrans Jump\ &back^T &Quay\ lại^T menutrans Build\ &Tags\ File &Tạo\ tập\ tin\ thẻ\ ghi "------------------- menutrans &Folding Nếp\ &gấp -menutrans &Diff &Khác\ biệt (diff) +menutrans &Diff &Khác\ biệt\ (diff) "------------------- menutrans &Make:make &Biên\ dịch:make menutrans &List\ Errors:cl &Danh\ sách\ lá»—i:cl diff --git a/runtime/lang/menu_zh_cn.utf-8.vim b/runtime/lang/menu_zh_cn.utf-8.vim index c8e2eb3828..f7b086d27d 100644 --- a/runtime/lang/menu_zh_cn.utf-8.vim +++ b/runtime/lang/menu_zh_cn.utf-8.vim @@ -1,7 +1,7 @@ " Menu Translations: Simplified Chinese " Maintainer: Shun Bai " Previous Maintainer: Yuheng Xie -" Last Change: 2019 Sep 11 +" Last Change: 2020 Apr 23 " Quit when menu translations have already been done. if exists("did_menu_trans") @@ -122,7 +122,7 @@ menutrans Toggle\ &C-Style\ Indenting:set\ cin! å¼€/å…³\ C\ 语言å¼ç¼© " other options menutrans &Shiftwidth 缩进宽度(&S) -menutrans Soft\ &Tabstop 软制表ä½å®½åº¦(Soft Tabstop)(&T) +menutrans Soft\ &Tabstop 软制表ä½å®½åº¦(Soft\ Tabstop)(&T) menutrans Te&xt\ Width\.\.\. 文本宽度(&X)\.\.\. menutrans &File\ Format\.\.\. 文件格å¼(&F)\.\.\. diff --git a/runtime/macros/less.vim b/runtime/macros/less.vim index 53857c6c08..5ba685cbc3 100644 --- a/runtime/macros/less.vim +++ b/runtime/macros/less.vim @@ -1,6 +1,6 @@ " Vim script to work like "less" " Maintainer: Bram Moolenaar -" Last Change: 2017 Mar 31 +" Last Change: 2020 May 18 " Avoid loading this file twice, allow the user to define his own script. if exists("loaded_less") @@ -66,8 +66,8 @@ endif " When reading from stdin don't consider the file modified. au VimEnter * set nomod -" Can't modify the text -set noma +" Can't modify the text or write the file. +set nomodifiable readonly " Give help noremap h :call Help() diff --git a/runtime/macros/life/life.vim b/runtime/macros/life/life.vim index 4c7e5ca46c..29832f0227 100644 --- a/runtime/macros/life/life.vim +++ b/runtime/macros/life/life.vim @@ -108,8 +108,9 @@ map ,o oPut 'X's in the left box, then hit 'C' or 'R' map ,R 03stop " " Write a new line (used by 'I'nitialize board) +" In remembrance of John Conway, 26 December 1937 – 11 April 2020. map )0 o- --....................--....................- -map )1 o- VIM --....................--....................- +map )1 o- JOHN CONWAY --....................--....................- map )2 o- LIVES --....................--....................- " " diff --git a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim index 3ba1f7e1d4..479b35c3f7 100644 --- a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim +++ b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim @@ -2,7 +2,7 @@ " " Author: Bram Moolenaar " Copyright: Vim license applies, see ":help license" -" Last Change: 2020 Feb 19 +" Last Change: 2020 May 22 " " WORK IN PROGRESS - Only the basics work " Note: On MS-Windows you need a recent version of gdb. The one included with @@ -657,8 +657,10 @@ func s:InstallCommands() command Source call s:GotoSourcewinOrCreateIt() command Winbar call s:InstallWinbar() - " TODO: can the K mapping be restored? - nnoremap K :Evaluate + if !exists('g:termdebug_map_K') || g:termdebug_map_K + let s:k_map_saved = maparg('K', 'n', 0, 1) + nnoremap K :Evaluate + endif if has('menu') && &mouse != '' call s:InstallWinbar() @@ -708,7 +710,10 @@ func s:DeleteCommands() delcommand Source delcommand Winbar - nunmap K + if exists('s:k_map_saved') + call mapset('n', 0, s:k_map_saved) + unlet s:k_map_saved + endif if has('menu') " Remove the WinBar entries from all windows where it was added. diff --git a/runtime/plugin/gzip.vim b/runtime/plugin/gzip.vim index 5e13b92d1e..7214488579 100644 --- a/runtime/plugin/gzip.vim +++ b/runtime/plugin/gzip.vim @@ -20,7 +20,7 @@ augroup gzip " " Set binary mode before reading the file. " Use "gzip -d", gunzip isn't always available. - autocmd BufReadPre,FileReadPre *.gz,*.bz2,*.Z,*.lzma,*.xz,*.lz,*.zst setlocal bin + autocmd BufReadPre,FileReadPre *.gz,*.bz2,*.Z,*.lzma,*.xz,*.lz,*.zst,*.br,*.lzo setlocal bin autocmd BufReadPost,FileReadPost *.gz call gzip#read("gzip -dn") autocmd BufReadPost,FileReadPost *.bz2 call gzip#read("bzip2 -d") autocmd BufReadPost,FileReadPost *.Z call gzip#read("uncompress") @@ -28,6 +28,8 @@ augroup gzip autocmd BufReadPost,FileReadPost *.xz call gzip#read("xz -d") autocmd BufReadPost,FileReadPost *.lz call gzip#read("lzip -d") autocmd BufReadPost,FileReadPost *.zst call gzip#read("zstd -d --rm") + autocmd BufReadPost,FileReadPost *.br call gzip#read("brotli -d --rm") + autocmd BufReadPost,FileReadPost *.lzo call gzip#read("lzop -d -U") autocmd BufWritePost,FileWritePost *.gz call gzip#write("gzip") autocmd BufWritePost,FileWritePost *.bz2 call gzip#write("bzip2") autocmd BufWritePost,FileWritePost *.Z call gzip#write("compress -f") @@ -35,6 +37,8 @@ augroup gzip autocmd BufWritePost,FileWritePost *.xz call gzip#write("xz -z") autocmd BufWritePost,FileWritePost *.lz call gzip#write("lzip") autocmd BufWritePost,FileWritePost *.zst call gzip#write("zstd --rm") + autocmd BufWritePost,FileWritePost *.br call gzip#write("brotli --rm") + autocmd BufWritePost,FileWritePost *.lzo call gzip#write("lzop -U") autocmd FileAppendPre *.gz call gzip#appre("gzip -dn") autocmd FileAppendPre *.bz2 call gzip#appre("bzip2 -d") autocmd FileAppendPre *.Z call gzip#appre("uncompress") @@ -42,6 +46,8 @@ augroup gzip autocmd FileAppendPre *.xz call gzip#appre("xz -d") autocmd FileAppendPre *.lz call gzip#appre("lzip -d") autocmd FileAppendPre *.zst call gzip#appre("zstd -d --rm") + autocmd FileAppendPre *.br call gzip#appre("brotli -d --rm") + autocmd FileAppendPre *.lzo call gzip#appre("lzop -d -U") autocmd FileAppendPost *.gz call gzip#write("gzip") autocmd FileAppendPost *.bz2 call gzip#write("bzip2") autocmd FileAppendPost *.Z call gzip#write("compress -f") @@ -49,4 +55,6 @@ augroup gzip autocmd FileAppendPost *.xz call gzip#write("xz -z") autocmd FileAppendPost *.lz call gzip#write("lzip") autocmd FileAppendPost *.zst call gzip#write("zstd --rm") + autocmd FileAppendPost *.br call gzip#write("brotli --rm") + autocmd FileAppendPost *.lzo call gzip#write("lzop -U") augroup END diff --git a/runtime/syntax/asciidoc.vim b/runtime/syntax/asciidoc.vim index ccb079e06b..29451f9eab 100644 --- a/runtime/syntax/asciidoc.vim +++ b/runtime/syntax/asciidoc.vim @@ -1,13 +1,15 @@ " Vim syntax file -" Language: AsciiDoc -" Author: Stuart Rackham (inspired by Felix -" Obenhuber's original asciidoc.vim script). -" URL: http://asciidoc.org/ -" Licence: GPL (http://www.gnu.org) -" Remarks: Vim 6 or greater -" Last Update: 2014 Aug 29 (see Issue 240) +" Language: AsciiDoc +" Maintainer: @aerostitch on GitHub (tag me in your issue in the +" github/vim/vim repository and I'll answer when available) +" Original author: Stuart Rackham (inspired by Felix +" Obenhuber's original asciidoc.vim script). +" URL: http://asciidoc.org/ +" Licence: GPL (http://www.gnu.org) +" Remarks: Vim 6 or greater +" Last Update: 2020 May 03 (see Issue 240) " Limitations: -" +" " - Nested quoted text formatting is highlighted according to the outer " format. " - If a closing Example Block delimiter may be mistaken for a title @@ -23,9 +25,7 @@ if exists("b:current_syntax") finish endif -syn clear -syn sync fromstart -syn sync linebreaks=100 +" Use the default syntax syncing. " Run :help syn-priority to review syntax matching priority. syn keyword asciidocToDo TODO FIXME CHECK TEST XXX ZZZ DEPRECATED diff --git a/runtime/syntax/debchangelog.vim b/runtime/syntax/debchangelog.vim index 8d282da445..7321e90b30 100644 --- a/runtime/syntax/debchangelog.vim +++ b/runtime/syntax/debchangelog.vim @@ -3,7 +3,7 @@ " Maintainer: Debian Vim Maintainers " Former Maintainers: Gerfried Fuchs " Wichert Akkerman -" Last Change: 2020 Feb 02 +" Last Change: 2020 Apr 27 " URL: https://salsa.debian.org/vim-team/vim-debian/blob/master/syntax/debchangelog.vim " Standard syntax initialization @@ -24,7 +24,7 @@ let s:supported = [ \ 'wheezy', 'jessie', 'stretch', 'buster', 'bullseye', 'bookworm', \ 'sid', 'rc-buggy', \ - \ 'trusty', 'xenial', 'bionic', 'eoan', 'focal', 'devel' + \ 'trusty', 'xenial', 'bionic', 'eoan', 'focal', 'groovy', 'devel' \ ] let s:unsupported = [ \ 'frozen', 'buzz', 'rex', 'bo', 'hamm', 'slink', 'potato', diff --git a/runtime/syntax/debsources.vim b/runtime/syntax/debsources.vim index e97d3274ba..b594443119 100644 --- a/runtime/syntax/debsources.vim +++ b/runtime/syntax/debsources.vim @@ -2,7 +2,7 @@ " Language: Debian sources.list " Maintainer: Debian Vim Maintainers " Former Maintainer: Matthijs Mohlmann -" Last Change: 2020 Feb 02 +" Last Change: 2020 Apr 27 " URL: https://salsa.debian.org/vim-team/vim-debian/blob/master/syntax/debsources.vim " Standard syntax initialization @@ -26,7 +26,7 @@ let s:supported = [ \ 'wheezy', 'jessie', 'stretch', 'buster', 'bullseye', 'bookworm', \ 'sid', 'rc-buggy', \ - \ 'trusty', 'xenial', 'bionic', 'eoan', 'focal', 'devel' + \ 'trusty', 'xenial', 'bionic', 'eoan', 'focal', 'groovy', 'devel' \ ] let s:unsupported = [ \ 'buzz', 'rex', 'bo', 'hamm', 'slink', 'potato', diff --git a/runtime/syntax/fortran.vim b/runtime/syntax/fortran.vim index 019a0bf2ac..2b62226ed4 100644 --- a/runtime/syntax/fortran.vim +++ b/runtime/syntax/fortran.vim @@ -1,7 +1,8 @@ " Vim syntax file " Language: Fortran 2008 (and older: Fortran 2003, 95, 90, and 77) " Version: 102 -" Last Change: 2019 Dec. 14 +" Last Change: 2020 Apr 20 +" Patched By: Eisuke Kawashima " Maintainer: Ajit J. Thakkar ; " Usage: For instructions, do :help fortran-syntax from Vim " Credits: @@ -53,10 +54,10 @@ if !exists("b:fortran_fixed_source") elseif exists("fortran_fixed_source") " User guarantees fixed source form for all fortran files let b:fortran_fixed_source = 1 - elseif expand("%:e") ==? "f\<90\|95\|03\|08\>" + elseif expand("%:e") =~? '^f\%(90\|95\|03\|08\)$' " Free-form file extension defaults as in Intel ifort, gcc(gfortran), NAG, Pathscale, and Cray compilers let b:fortran_fixed_source = 0 - elseif expand("%:e") ==? "f\|f77\|for" + elseif expand("%:e") =~? '^\%(f\|f77\|for\)$' " Fixed-form file extension defaults let b:fortran_fixed_source = 1 else diff --git a/runtime/syntax/gnuplot.vim b/runtime/syntax/gnuplot.vim index 7777cc9e46..9c98e67e58 100644 --- a/runtime/syntax/gnuplot.vim +++ b/runtime/syntax/gnuplot.vim @@ -3,7 +3,7 @@ " Maintainer: Josh Wainwright " Last Maintainer: Andrew Rasmussen andyras@users.sourceforge.net " Original Maintainer: John Hoelzel johnh51@users.sourceforge.net -" Last Change: 2015-08-25 +" Last Change: 2020 May 12 " Filenames: *.gnu *.plt *.gpi *.gih *.gp *.gnuplot scripts: #!*gnuplot " URL: http://www.vim.org/scripts/script.php?script_id=4873 " Original URL: http://johnh51.get.to/vim/syntax/gnuplot.vim @@ -479,7 +479,7 @@ syn keyword gnuplotKeyword terminal palette rgb rbg grb gbr brg bgr " ---- Macros ---- " -syn region gnuplotMacro start="@" end=" " +syn match gnuplotMacro "@[a-zA-Z0-9_]*" " ---- Todos ---- " diff --git a/runtime/syntax/groovy.vim b/runtime/syntax/groovy.vim index 2245b79d04..9bc1bd6d8d 100644 --- a/runtime/syntax/groovy.vim +++ b/runtime/syntax/groovy.vim @@ -1,10 +1,10 @@ " Vim syntax file " Language: Groovy -" Original Author: Alessio Pace -" Maintainer: Tobias Rapp -" Version: 0.1.16 +" Original Author: Alessio Pace +" Maintainer: Tobias Rapp +" Version: 0.1.17 " URL: http://www.vim.org/scripts/script.php?script_id=945 -" Last Change: 2016 May 23 +" Last Change: 2020 May 26 " THE ORIGINAL AUTHOR'S NOTES: " @@ -253,7 +253,7 @@ if exists("groovy_regex_strings") endif " syn region groovyELExpr start=+${+ end=+}+ keepend contained syn match groovyELExpr /\${.\{-}}/ contained -syn match groovyELExpr /\$[a-zA-Z_][a-zA-Z0-9_.]*/ contained +syn match groovyELExpr /\$[a-zA-Z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0100-\uFFFE_][a-zA-Z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0100-\uFFFE0-9_.]*/ contained hi def link groovyELExpr Identifier " TODO: better matching. I am waiting to understand how it really works in groovy diff --git a/runtime/syntax/javascript.vim b/runtime/syntax/javascript.vim index 5c6439f9e0..8a5e10b261 100644 --- a/runtime/syntax/javascript.vim +++ b/runtime/syntax/javascript.vim @@ -7,7 +7,7 @@ " (ss) repaired several quoting and grouping glitches " (ss) fixed regex parsing issue with multiple qualifiers [gi] " (ss) additional factoring of keywords, globals, and members -" Last Change: 2019 Sep 27 +" Last Change: 2020 May 14 " 2013 Jun 12: adjusted javaScriptRegexpString (Kevin Locke) " 2018 Apr 14: adjusted javaScriptRegexpString (LongJohnCoder) @@ -77,10 +77,10 @@ else syn match javaScriptParens "[()]" endif -syn sync fromstart -syn sync maxlines=100 - if main_syntax == "javascript" + syn sync fromstart + syn sync maxlines=100 + syn sync ccomment javaScriptComment endif diff --git a/runtime/syntax/lex.vim b/runtime/syntax/lex.vim index 9e0b307d68..dff70eb3b7 100644 --- a/runtime/syntax/lex.vim +++ b/runtime/syntax/lex.vim @@ -1,22 +1,19 @@ " Vim syntax file -" Language: Lex +" Language: Lex and Flex " Maintainer: Charles E. Campbell -" Last Change: Aug 31, 2016 -" Version: 17 -" URL: http://mysite.verizon.net/astronaut/vim/index.html#SYNTAX_LEX -" -" Option: -" lex_uses_cpp : if this variable exists, then C++ is loaded rather than C +" Contributor: Robert A. van Engelen +" Last Change: Apr 24, 2020 +" Version: 18 " quit when a syntax file was already loaded if exists("b:current_syntax") finish endif -" Read the C/C++ syntax to start with -let s:Cpath= fnameescape(expand(":p:h").(exists("g:lex_uses_cpp")? "/cpp.vim" : "/c.vim")) +" Read the C++ syntax to start with +let s:Cpath= fnameescape(expand(":p:h")."/cpp.vim") if !filereadable(s:Cpath) - for s:Cpath in split(globpath(&rtp,(exists("g:lex_uses_cpp")? "syntax/cpp.vim" : "syntax/c.vim")),"\n") + for s:Cpath in split(globpath(&rtp,"syntax/cpp.vim"),"\n") if filereadable(fnameescape(s:Cpath)) let s:Cpath= fnameescape(s:Cpath) break @@ -29,115 +26,163 @@ exe "syn include @lexCcode ".s:Cpath " --- Lex stuff --- " --- ========= --- -" Options Section -syn match lexOptions '^%\s*option\>.*$' contains=lexPatString +" Definitions +" %% +" Rules +" %% +" User Code +" +" --- ======= --- +" --- Example --- +" --- ======= --- +" +" // this is a valid lex file +" // indented initial code block +" #include +" %{ +" // initial code block +" #include +" const char *sep = ""; +" %} +" %option outfile="scanner.c" noyywrap nodefault +" %x COMMENT +" id [A-Za-z_][A-Za-z0-9_]* +" %% +" // indented initial action code block +" printf("BEGIN"); +" {id} printf("%s%s", sep, yytext); sep = ""; +" . | +" \n { sep = "\n"; } +" "/*" { BEGIN COMMENT; } +" "//".* { } +" { +" "*/" { BEGIN INITIAL; } +" .|\n +" } +" <*><> { // end of file +" printf("\nEND\n"); +" yyterminate(); +" } +" %% +" void scan() +" { +" while (yylex()) +" continue; +" } +" /* main program */ +" int main() +" { +" scan(); +" } -" Abbreviations Section +" Definitions Section with initial code blocks, abbreviations, options, states if has("folding") - syn region lexAbbrvBlock fold start="^\(\h\+\s\|%{\)" end="^\ze%%$" skipnl nextgroup=lexPatBlock contains=lexAbbrv,lexInclude,lexAbbrvComment,lexStartState + syn region lexAbbrvBlock fold start="^\S" end="^\ze%%" skipnl nextgroup=lexPatBlock contains=lexOptions,lexAbbrv,lexInitialCodeBlock,lexInclude,lexAbbrvComment,lexStartState else - syn region lexAbbrvBlock start="^\(\h\+\s\|%{\)" end="^\ze%%$" skipnl nextgroup=lexPatBlock contains=lexAbbrv,lexInclude,lexAbbrvComment,lexStartState + syn region lexAbbrvBlock start="^\S" end="^\ze%%" skipnl nextgroup=lexPatBlock contains=lexOptions,lexAbbrv,lexInitialCodeBlock,lexInclude,lexAbbrvComment,lexStartState endif -syn match lexAbbrv "^\I\i*\s"me=e-1 skipwhite contained nextgroup=lexAbbrvRegExp -syn match lexAbbrv "^%[sx]" contained -syn match lexAbbrvRegExp "\s\S.*$"lc=1 contained nextgroup=lexAbbrv,lexInclude +syn match lexOptions "^%\a\+\(\s.*\|[^{]*\)$" contains=lexOptionsEq,lexPatString,lexSlashQuote,lexBrace,lexSlashBrace +syn match lexOptionsEq "=" skipwhite contained +syn match lexAbbrv "^\I\i*\s"me=e-1 skipwhite contained nextgroup=lexAbbrvPat +syn match lexAbbrvPat "\s\S.*$"lc=1 contained contains=lexPatAbbrv,lexPatString,lexSlashQuote,lexBrace,lexSlashBrace nextgroup=lexAbbrv,lexInclude +syn match lexStartState "^%\(xs\?\|s\)\(t\(a\(t\(e\?\)\?\)\?\)\?\)\?\(\s\+\I\i*\)\+\s*$" contained contains=lexStartStateCmd +syn match lexStartStateCmd '^%\(xs\?\|s\)\(t\(a\(t\(e\?\)\?\)\?\)\?\)\?' contained if has("folding") - syn region lexInclude fold matchgroup=lexSep start="^%{" end="%}" contained contains=@lexCcode - syn region lexAbbrvComment fold start="^\s\+/\*" end="\*/" contains=@Spell - syn region lexAbbrvComment fold start="\%^/\*" end="\*/" contains=@Spell - syn region lexStartState fold matchgroup=lexAbbrv start="^%\a\+" end="$" contained + syn region lexInitialCodeBlock fold start="^\s\+" end="^\S"me=e-1 contains=@lexCcode + syn region lexInclude fold matchgroup=lexSep start="^%\a*{" end="^%\?}" contained contains=@lexCcode,lexCFunctions + syn region lexAbbrvComment fold start="^\s*//" end="$" contains=@Spell + syn region lexAbbrvComment fold start="^\s*/\*" end="\*/" contains=@Spell else - syn region lexInclude matchgroup=lexSep start="^%{" end="%}" contained contains=@lexCcode - syn region lexAbbrvComment start="^\s\+/\*" end="\*/" contains=@Spell - syn region lexAbbrvComment start="\%^/\*" end="\*/" contains=@Spell - syn region lexStartState matchgroup=lexAbbrv start="^%\a\+" end="$" contained + syn region lexInitialCodeBlock start="^\s\+" end="^\S"me=e-1 contains=@lexCcode + syn region lexInclude matchgroup=lexSep start="^%\a*{" end="^%\?}" contained contains=@lexCcode,lexCFunctions + syn region lexAbbrvComment start="^\s*//" end="$" contains=@Spell + syn region lexAbbrvComment start="^\s*/\*" end="\*/" contains=@Spell endif -"%% : Patterns {Actions} +" Rules Section with patterns and actions if has("folding") - syn region lexPatBlock fold matchgroup=Todo start="^%%$" matchgroup=Todo end="^%\ze%$" skipnl skipwhite nextgroup=lexFinalCodeBlock contains=lexPatTag,lexPatTagZone,lexPatComment,lexPat,lexPatInclude - syn region lexPat fold start=+\S+ skip="\\\\\|\\." end="\s"me=e-1 skipwhite contained nextgroup=lexMorePat,lexPatSep,lexPattern contains=lexPatTag,lexPatString,lexSlashQuote,lexBrace - syn region lexPatInclude fold matchgroup=lexSep start="^%{" end="%}" contained contains=lexPatCode - syn region lexBrace fold start="\[" skip=+\\\\\|\\+ end="]" contained - syn region lexPatString fold matchgroup=String start=+"+ skip=+\\\\\|\\"+ matchgroup=String end=+"+ contained + syn region lexPatBlock fold matchgroup=Todo start="^%%" matchgroup=Todo end="^\ze%%" skipnl skipwhite nextgroup=lexFinalCodeBlock contains=lexPatTag,lexPatTagZone,lexPatComment,lexPat,lexPatSep,lexPatInclude + syn region lexPat fold start="\S" skip="\\\\\|\\\s" end="\ze\(\s*$\|\s\+\(\h\|{\W\|{$\|[-+*]\|//\|/\*\)\)" skipwhite contained nextgroup=lexMorePat,lexPatSep,lexPatEnd contains=lexPatTag,lexPatString,lexSlashQuote,lexPatAbbrv,lexBrace,lexSlashBrace + syn region lexPatInclude fold matchgroup=lexSep start="^%{" end="^%}" contained contains=@lexCcode + syn region lexBrace fold matchgroup=Character start="\[" skip="\\.\|\[:\a\+:\]\|\[\.\a\+\.\]\|\[=.=\]" end="\]" contained + syn region lexPatString fold matchgroup=String start=+"+ skip=+\\\\\|\\"+ matchgroup=String end=+"+ contained else - syn region lexPatBlock matchgroup=Todo start="^%%$" matchgroup=Todo end="^%%$" skipnl skipwhite nextgroup=lexFinalCodeBlock contains=lexPatTag,lexPatTagZone,lexPatComment,lexPat,lexPatInclude - syn region lexPat start=+\S+ skip="\\\\\|\\." end="\s"me=e-1 skipwhite contained nextgroup=lexMorePat,lexPatSep,lexPattern contains=lexPatTag,lexPatString,lexSlashQuote,lexBrace - syn region lexPatInclude matchgroup=lexSep start="^%{" end="%}" contained contains=lexPatCode - syn region lexBrace start="\[" skip=+\\\\\|\\+ end="]" contained - syn region lexPatString matchgroup=String start=+"+ skip=+\\\\\|\\"+ matchgroup=String end=+"+ contained + syn region lexPatBlock matchgroup=Todo start="^%%" matchgroup=Todo end="^\ze%%" skipnl skipwhite nextgroup=lexFinalCodeBlock contains=lexPatTag,lexPatTagZone,lexPatComment,lexPat,lexPatSep,lexPatInclude + syn region lexPat start="\S" skip="\\\\\|\\\s" end="\ze\(\s*$\|\s\+\(\h\|{\W\|{$\|[-+*]\|//\|/\*\)\)" skipwhite contained nextgroup=lexMorePat,lexPatSep,lexPatEnd contains=lexPatTag,lexPatString,lexSlashQuote,lexPatAbbrv,lexBrace,lexSlashBrace + syn region lexPatInclude matchgroup=lexSep start="^%{" end="^%}" contained contains=@lexCcode + syn region lexBrace matchgroup=Character start="\[" skip="\\.\|\[:\a\+:\]\|\[\.\a\+\.\]\|\[=.=\]" end="\]" contained + syn region lexPatString matchgroup=String start=+"+ skip=+\\\\\|\\"+ matchgroup=String end=+"+ contained endif -syn match lexPatTag "^<\I\i*\(,\I\i*\)*>" contained nextgroup=lexPat,lexPatTag,lexMorePat,lexPatSep -syn match lexPatTagZone "^<\I\i*\(,\I\i*\)*>\s\+\ze{" contained nextgroup=lexPatTagZoneStart -syn match lexPatTag +^<\I\i*\(,\I\i*\)*>*\(\\\\\)*\\"+ contained nextgroup=lexPat,lexPatTag,lexMorePat,lexPatSep - -" Lex Patterns -syn region lexPattern start='[^ \t{}]' end="$" contained contains=lexPatRange -syn region lexPatRange matchgroup=Delimiter start='\[' skip='\\\\\|\\.' end='\]' contains=lexEscape -syn match lexEscape '\%(\\\\\)*\\.' contained +syn match lexPatAbbrv "{\I\i*}"hs=s+1,he=e-1 contained +syn match lexPatTag "^<\^\?\(\I\i*\|\*\)\(,\^\?\(\I\i*\|\*\)\)*>" contained nextgroup=lexPat,lexMorePat,lexPatSep,lexPatEnd +syn match lexPatTagZone "^<\^\?\(\I\i*\|\*\)\(,\^\?\(\I\i*\|\*\)\)*>\s*{$"me=e-1 contained nextgroup=lexPatTagZoneStart if has("folding") - syn region lexPatTagZoneStart matchgroup=lexPatTag fold start='{' end='}' contained contains=lexPat,lexPatComment - syn region lexPatComment start="\s\+/\*" end="\*/" fold skipnl contained contains=cTodo skipwhite nextgroup=lexPatComment,lexPat,@Spell + syn region lexPatTagZoneStart fold matchgroup=lexPatTag start='{$' end='^}' skipnl skipwhite contained contains=lexPatTag,lexPatTagZone,lexPatComment,lexPat,lexPatSep,lexPatInclude + syn region lexPatComment fold start="//" end="$" skipnl contained contains=cTodo skipwhite nextgroup=lexPatComment,lexPat,@Spell + syn region lexPatComment fold start="/\*" end="\*/" skipnl contained contains=cTodo skipwhite nextgroup=lexPatComment,lexPat,@Spell else - syn region lexPatTagZoneStart matchgroup=lexPatTag start='{' end='}' contained contains=lexPat,lexPatComment - syn region lexPatComment start="\s\+/\*" end="\*/" skipnl contained contains=cTodo skipwhite nextgroup=lexPatComment,lexPat,@Spell + syn region lexPatTagZoneStart matchgroup=lexPatTag start='{' end='^}' skipnl skipwhitecontained contains=lexPatTag,lexPatTagZone,lexPatComment,lexPat,lexPatSep,lexPatInclude + syn region lexPatComment start="//" end="$" skipnl contained contains=cTodo skipwhite nextgroup=lexPatComment,lexPat,@Spell + syn region lexPatComment start="/\*" end="\*/" skipnl contained contains=cTodo skipwhite nextgroup=lexPatComment,lexPat,@Spell endif -syn match lexPatCodeLine "[^{\[].*" contained contains=@lexCcode -syn match lexMorePat "\s*|\s*$" skipnl contained nextgroup=lexPat,lexPatTag,lexPatComment -syn match lexPatSep "\s\+" contained nextgroup=lexMorePat,lexPatCode,lexPatCodeLine +syn match lexPatEnd "\s*$" skipnl contained +syn match lexPatCodeLine "[^{\[].*" contained contains=@lexCcode,lexCFunctions +syn match lexMorePat "\s*|\s*$" skipnl contained nextgroup=lexPat,lexPatTag,lexPatComment +syn match lexPatSep "\s\+" contained nextgroup=lexMorePat,lexPatCode,lexPatCodeLine syn match lexSlashQuote +\(\\\\\)*\\"+ contained +syn match lexSlashBrace +\(\\\\\)*\\\[+ contained if has("folding") - syn region lexPatCode matchgroup=Delimiter start="{" end="}" fold skipnl contained contains=@lexCcode,lexCFunctions + syn region lexPatCode fold matchgroup=Delimiter start="{" end="}" skipnl contained contains=@lexCcode,lexCFunctions else - syn region lexPatCode matchgroup=Delimiter start="{" end="}" skipnl contained contains=@lexCcode,lexCFunctions + syn region lexPatCode matchgroup=Delimiter start="{" end="}" skipnl contained contains=@lexCcode,lexCFunctions endif -" Lex "functions" which may appear in C/C++ code blocks -syn keyword lexCFunctions BEGIN input unput woutput yyleng yylook yytext -syn keyword lexCFunctions ECHO output winput wunput yyless yymore yywrap +" User Code Section with final code block +syn region lexFinalCodeBlock matchgroup=Todo start="^%%" end="\%$" contained contains=@lexCcode -" %% -" lexAbbrevBlock -" %% -" lexPatBlock -" %% -" lexFinalCodeBlock -syn region lexFinalCodeBlock matchgroup=Todo start="%$"me=e-1 end="\%$" contained contains=@lexCcode +" Lex macros which may appear in C/C++ code blocks +syn keyword lexCFunctions BEGIN ECHO REJECT yytext YYText yyleng YYLeng yymore yyless yywrap yylook +syn keyword lexCFunctions yyrestart yyterminate yylineno yycolumno yyin yyout +syn keyword lexCFunctions input unput output winput wunput woutput +syn keyword lexCFunctions yyinput yyunput yyoutput yywinput yywunput yywoutput " includes several ALLBUTs; these have to be treated so as to exclude lex* groups -syn cluster cParenGroup add=lex.* +syn cluster cParenGroup add=lex.* syn cluster cDefineGroup add=lex.* syn cluster cPreProcGroup add=lex.* -syn cluster cMultiGroup add=lex.* +syn cluster cMultiGroup add=lex.* " Synchronization syn sync clear syn sync minlines=500 syn sync match lexSyncPat grouphere lexPatBlock "^%[a-zA-Z]" syn sync match lexSyncPat groupthere lexPatBlock "^<$" -syn sync match lexSyncPat groupthere lexPatBlock "^%%$" +syn sync match lexSyncPat groupthere lexPatBlock "^%%" " The default highlighting. if !exists("skip_lex_syntax_inits") hi def link lexAbbrvComment lexPatComment - hi def link lexAbbrvRegExp Macro - hi def link lexAbbrv SpecialChar - hi def link lexBrace lexPat - hi def link lexCFunctions Function - hi def link lexCstruct cStructure - hi def link lexMorePat SpecialChar - hi def link lexOptions PreProc + hi def link lexAbbrvPat lexPat + hi def link lexAbbrv Special + hi def link lexBrace lexPat + hi def link lexCFunctions PreProc + hi def link lexMorePat Special + hi def link lexOptions PreProc + hi def link lexOptionsEq Operator hi def link lexPatComment Comment hi def link lexPat Function - hi def link lexPatString Function - hi def link lexPatTag Special + hi def link lexPatString lexPat + hi def link lexPatAbbrv Special + hi def link lexPatTag Statement hi def link lexPatTagZone lexPatTag hi def link lexSep Delimiter hi def link lexSlashQuote lexPat - hi def link lexStartState Statement + hi def link lexSlashBrace lexPat + hi def link lexStartState lexPatTag + hi def link lexStartStateCmd Special endif let b:current_syntax = "lex" -" vim:ts=10 +" vim:ts=8 diff --git a/runtime/syntax/make.vim b/runtime/syntax/make.vim index 2a64dcd85c..d0d7f1523b 100644 --- a/runtime/syntax/make.vim +++ b/runtime/syntax/make.vim @@ -3,7 +3,7 @@ " Maintainer: Roland Hieber , " Previous Maintainer: Claudio Fleiner " URL: https://github.com/vim/vim/blob/master/runtime/syntax/make.vim -" Last Change: 2020 Mar 04 +" Last Change: 2020 May 03 " quit when a syntax file was already loaded if exists("b:current_syntax") @@ -73,7 +73,7 @@ syn match makePreCondit "^ *\(ifn\=\(eq\|def\)\>\|else\(\s\+ifn\=\(eq\|def\)\)\= syn match makeInclude "^ *[-s]\=include\s.*$" syn match makeStatement "^ *vpath" syn match makeExport "^ *\(export\|unexport\)\>" -syn match makeOverride "^ *override" +syn match makeOverride "^ *override\>" " Statements / Functions (GNU make) syn match makeStatement contained "(\(abspath\|addprefix\|addsuffix\|and\|basename\|call\|dir\|error\|eval\|file\|filter-out\|filter\|findstring\|firstword\|flavor\|foreach\|guile\|if\|info\|join\|lastword\|notdir\|or\|origin\|patsubst\|realpath\|shell\|sort\|strip\|subst\|suffix\|value\|warning\|wildcard\|word\|wordlist\|words\)\>"ms=s+1 diff --git a/runtime/syntax/man.vim b/runtime/syntax/man.vim index 77675c5d2f..56f6d10de2 100644 --- a/runtime/syntax/man.vim +++ b/runtime/syntax/man.vim @@ -1,9 +1,10 @@ " Vim syntax file " Language: Man page -" Maintainer: SungHyun Nam +" Maintainer: Jason Franklin +" Previous Maintainer: SungHyun Nam " Previous Maintainer: Gautam H. Mudunuri " Version Info: -" Last Change: 2015 Nov 24 +" Last Change: 2020 Apr 30 " Additional highlighting by Johannes Tanzler : " * manSubHeading @@ -18,14 +19,17 @@ endif runtime! syntax/ctrlh.vim syn case ignore + syn match manReference "\f\+([1-9][a-z]\=)" -syn match manTitle "^\f\+([0-9]\+[a-z]\=).*" syn match manSectionHeading "^[a-z][a-z -]*[a-z]$" syn match manSubHeading "^\s\{3\}[a-z][a-z -]*[a-z]$" syn match manOptionDesc "^\s*[+-][a-z0-9]\S*" syn match manLongOptionDesc "^\s*--[a-z0-9-]\S*" " syn match manHistory "^[a-z].*last change.*$" +syn match manHeader '\%1l.*' +exe 'syn match manFooter ''\%' . line('$') . 'l.*''' + if getline(1) =~ '^[a-zA-Z_]\+([23])' syntax include @cCode :p:h/c.vim syn match manCFuncDefinition display "\<\h\w*\>\s*("me=e-1 contained @@ -36,7 +40,9 @@ endif " Define the default highlighting. " Only when an item doesn't have highlighting yet -hi def link manTitle Title +hi def link manHeader Title +hi def link manFooter PreProc + hi def link manSectionHeading Statement hi def link manOptionDesc Constant hi def link manLongOptionDesc Constant diff --git a/runtime/syntax/masm.vim b/runtime/syntax/masm.vim index bb3c9681bc..c3b2a9bd63 100644 --- a/runtime/syntax/masm.vim +++ b/runtime/syntax/masm.vim @@ -2,8 +2,7 @@ " Language: Microsoft Macro Assembler (80x86) " Orig Author: Rob Brady " Maintainer: Wu Yongwei -" Last Change: $Date: 2013/11/13 11:49:24 $ -" $Revision: 1.48 $ +" Last Change: 2020-05-09 22:55:38 +0800 " Quit when a syntax file was already loaded if exists("b:current_syntax") @@ -13,10 +12,12 @@ endif let s:cpo_save = &cpo set cpo&vim +syn iskeyword @,48-57,_,36,60,62,63,@-@ + syn case ignore -syn match masmIdentifier "[@a-z_$?][@a-z0-9_$?]*" +syn match masmIdentifier "[@a-z_$?][@a-z0-9_$?<>]*" syn match masmLabel "^\s*[@a-z_$?][@a-z0-9_$?]*:"he=e-1 syn match masmDecimal "[-+]\?\d\+[dt]\?" diff --git a/runtime/syntax/pamenv.vim b/runtime/syntax/pamenv.vim new file mode 100644 index 0000000000..90359daa61 --- /dev/null +++ b/runtime/syntax/pamenv.vim @@ -0,0 +1,28 @@ +" Vim syntax file +" Language: pam_env.conf(5) configuration file +" Latest Revision: 2020-05-10 + +if exists("b:current_syntax") + finish +endif + +syn keyword pamenvTodo contained TODO FIXME XXX NOTE +syn region pamenvComment start='^#' end='$' display oneline contains=pamenvTodo,@Spells + +syn match pamenvVars '^[A-Z_][A-Z_0-9]*' nextgroup=pamenvKeywords skipwhite + +syn keyword pamenvKeywords contained DEFAULT OVERRIDE nextgroup=pamenvVarEq + +syn match pamenvVarEq contained '=' nextgroup=pamenvValue,pamenvValueWithQuote + +syn match pamenvValue contained '[^ \t]*' skipwhite nextgroup=pamenvKeywords +syn region pamenvValueWithQuote contained start='"' end='"' skipwhite nextgroup=pamenvKeywords + +hi def link pamenvTodo Todo +hi def link pamenvComment Comment +hi def link pamenvKeywords Keyword +hi def link pamenvVars Identifier +hi def link pamenvValue String +hi def link pamenvValueWithQuote String + +let b:current_syntax = "pamenv" diff --git a/runtime/syntax/perl.vim b/runtime/syntax/perl.vim index 6ac28f6915..f4f9520de5 100644 --- a/runtime/syntax/perl.vim +++ b/runtime/syntax/perl.vim @@ -1,9 +1,9 @@ " Vim syntax file " Language: Perl 5 " Maintainer: vim-perl -" Homepage: http://github.com/vim-perl/vim-perl/tree/master -" Bugs/requests: http://github.com/vim-perl/vim-perl/issues -" Last Change: 2017-09-12 +" Homepage: https://github.com/vim-perl/vim-perl/tree/master +" Bugs/requests: https://github.com/vim-perl/vim-perl/issues +" Last Change: 2020 Apr 15 " Contributors: Andy Lester " Hinrik Örn Sigurðsson " Lukas Mai diff --git a/runtime/syntax/perl6.vim b/runtime/syntax/perl6.vim index 3bcd9ff0e9..62ddc456e2 100644 --- a/runtime/syntax/perl6.vim +++ b/runtime/syntax/perl6.vim @@ -1,9 +1,9 @@ " Vim syntax file " Language: Perl 6 " Maintainer: vim-perl -" Homepage: http://github.com/vim-perl/vim-perl/tree/master -" Bugs/requests: http://github.com/vim-perl/vim-perl/issues -" Last Change: 2013-07-21 +" Homepage: https://github.com/vim-perl/vim-perl/tree/master +" Bugs/requests: https://github.com/vim-perl/vim-perl/issues +" Last Change: 2020 Apr 15 " Contributors: Luke Palmer " Moritz Lenz diff --git a/runtime/syntax/php.vim b/runtime/syntax/php.vim index 04036fdf39..720d71e646 100644 --- a/runtime/syntax/php.vim +++ b/runtime/syntax/php.vim @@ -1,9 +1,11 @@ " Vim syntax file " Language: php PHP 3/4/5/7 -" Maintainer: Jason Woofenden -" Last Change: Oct 19, 2019 -" URL: https://jasonwoof.com/gitweb/?p=vim-syntax.git;a=blob;f=php.vim;hb=HEAD -" Former Maintainers: Peter Hodge +" Maintainer: Tyson Andre +" Last Change: May 11, 2020 +" URL: https://github.com/TysonAndre/vim-syntax +" Former Maintainers: +" Jason Woofenden +" Peter Hodge " Debian VIM Maintainers " " Note: If you are using a colour terminal with dark background, you will @@ -91,7 +93,7 @@ if exists( "php_htmlInStrings") syn cluster phpAddStrings add=@htmlTop endif -" make sure we can use \ at the begining of the line to do a continuation +" make sure we can use \ at the beginning of the line to do a continuation let s:cpo_save = &cpo set cpo&vim @@ -314,7 +316,7 @@ syn region phpIdentifierComplexP matchgroup=phpParent start="\[" end="]" contain " define a cluster to get all interpolation syntaxes for double-quoted strings syn cluster phpInterpDouble contains=phpInterpSimple,phpInterpSimpleCurly,phpInterpDollarCurly1,phpInterpDollarCurly2,phpInterpBogusDollarCurley,phpInterpComplex -" Methoden +" Methods syn match phpMethodsVar "->\h\w*" contained contains=phpMethods,phpMemberSelector display " Include @@ -328,14 +330,14 @@ syn keyword phpBoolean true false contained " Float " Refer to: https://www.php.net/manual/en/language.types.float.php -syn match phpFloat "\%(\w\|\.\)\@\|[eE]\)\|\(\>\|[eE]\)_\)" contained display " Number -syn match phpNumber "\%(\.\)\@\%(\.\)\@!" contained display +syn match phpNumber "\%(\.\)\@\%(\.\)\@!" contained display syn match phpNumber "\%(\.\)\@\%(\.\)\@!" contained contains=phpOctalError display syn match phpBinaryError "[2-9]" contained display -syn match phpNumber "\%(\.\)\@\%(\.\)\@!" contained contains=phpBinaryError display +syn match phpNumber "\%(\.\)\@\%(\.\)\@!" contained contains=phpBinaryError display " Backslash escapes syn case match @@ -442,6 +444,7 @@ if exists("php_folding") && php_folding==1 " match one line constructs here and skip them at folding syn keyword phpSCKeyword abstract final private protected public static contained syn keyword phpFCKeyword function contained + syn keyword phpDefine fn contained syn keyword phpStorageClass global contained syn match phpDefine "\(\s\|^\)\(abstract\s\+\|final\s\+\|private\s\+\|protected\s\+\|public\s\+\|static\s\+\)*function\(\s\+.*[;}]\)\@=" contained contains=phpSCKeyword syn match phpStructure "\(\s\|^\)\(abstract\s\+\|final\s\+\)*\(trait\|class\)\(\s\+.*}\)\@=" contained @@ -459,7 +462,7 @@ if exists("php_folding") && php_folding==1 syn region phpFoldCatch matchgroup=Exception start="^\z(\s*\)catch\s\+\([^}]*$\)\@=" matchgroup=Delimiter end="^\z1}" contains=@phpClFunction,phpFoldFunction contained transparent fold extend syn region phpFoldTry matchgroup=Exception start="^\z(\s*\)try\s\+\([^}]*$\)\@=" matchgroup=Delimiter end="^\z1}" contains=@phpClFunction,phpFoldFunction contained transparent fold extend else - syn keyword phpDefine function contained + syn keyword phpDefine function fn contained syn keyword phpStructure abstract class trait interface contained syn keyword phpException catch throw try finally contained syn keyword phpStorageClass final global private protected public static contained diff --git a/runtime/syntax/sh.vim b/runtime/syntax/sh.vim index 0f4406d3e1..3a2a6e7b0e 100644 --- a/runtime/syntax/sh.vim +++ b/runtime/syntax/sh.vim @@ -2,8 +2,8 @@ " Language: shell (sh) Korn shell (ksh) bash (sh) " Maintainer: Charles E. Campbell " Previous Maintainer: Lennart Schultz -" Last Change: Oct 16, 2019 -" Version: 189 +" Last Change: Apr 14, 2020 +" Version: 190 " URL: http://www.drchip.org/astronaut/vim/index.html#SYNTAX_SH " For options and settings, please use: :help ft-sh-syntax " This file includes many ideas from Eric Brunet (eric.brunet@ens.fr) @@ -357,19 +357,18 @@ elseif !exists("g:sh_no_error") syn region shExDoubleQuote matchGroup=Error start=+\$"+ skip=+\\\\\|\\.+ end=+"+ contains=shStringSpecial endif syn region shSingleQuote matchgroup=shQuote start=+'+ end=+'+ contains=@Spell nextgroup=shSpecialStart,shSpecialSQ -syn region shDoubleQuote matchgroup=shQuote start=+\%(\%(\\\\\)*\\\)\@ -" Last Change: 2016 Nov 04 +" Last Change: 2020 Apr 13 " This file sets up for syntax highlighting. " It is loaded from "syntax.vim" and "manual.vim". @@ -52,9 +52,11 @@ fun! s:SynSet() if s != "" " Load the syntax file(s). When there are several, separated by dots, - " load each in sequence. + " load each in sequence. Skip empty entries. for name in split(s, '\.') - exe "runtime! syntax/" . name . ".vim syntax/" . name . "/*.vim" + if !empty(name) + exe "runtime! syntax/" . name . ".vim syntax/" . name . "/*.vim" + endif endfor endif endfun diff --git a/runtime/syntax/tex.vim b/runtime/syntax/tex.vim index 83f6f82547..22b43aa38b 100644 --- a/runtime/syntax/tex.vim +++ b/runtime/syntax/tex.vim @@ -1,8 +1,8 @@ " Vim syntax file " Language: TeX " Maintainer: Charles E. Campbell -" Last Change: Jan 24, 2020 -" Version: 116 +" Last Change: May 19, 2020 +" Version: 117 " URL: http://www.drchip.org/astronaut/vim/index.html#SYNTAX_TEX " " Notes: {{{1 @@ -1057,6 +1057,7 @@ if has("conceal") && &enc == 'utf-8' call s:SuperSub('texSuperscript','\^','R','á´¿') call s:SuperSub('texSuperscript','\^','T','áµ€') call s:SuperSub('texSuperscript','\^','U','áµ') + call s:SuperSub('texSuperscript','\^','V','â±½') call s:SuperSub('texSuperscript','\^','W','ᵂ') call s:SuperSub('texSuperscript','\^',',','ï¸') call s:SuperSub('texSuperscript','\^',':','︓') diff --git a/runtime/syntax/vim.vim b/runtime/syntax/vim.vim index d99dc12788..1eef428112 100644 --- a/runtime/syntax/vim.vim +++ b/runtime/syntax/vim.vim @@ -1,8 +1,8 @@ " Vim syntax file " Language: Vim 8.0 script -" Maintainer: Charles E. Campbell -" Last Change: March 11, 2020 -" Version: 8.0-30 +" Maintainer: Charles E. Campbell +" Last Change: May 26, 2020 +" Version: 8.0-35 " URL: http://www.drchip.org/astronaut/vim/index.html#SYNTAX_VIM " Automatically generated keyword lists: {{{1 @@ -224,11 +224,11 @@ syn keyword vimAugroupKey contained aug[roup] " Operators: {{{2 " ========= -syn cluster vimOperGroup contains=vimEnvvar,vimFunc,vimFuncVar,vimOper,vimOperParen,vimNumber,vimString,vimRegister,vimContinue +syn cluster vimOperGroup contains=vimEnvvar,vimFunc,vimFuncVar,vimOper,vimOperParen,vimNumber,vimString,vimRegister,vimContinue,vim9Comment syn match vimOper "\%#=1\(==\|!=\|>=\|<=\|=\~\|!\~\|>\|<\|=\)[?#]\{0,2}" skipwhite nextgroup=vimString,vimSpecFile syn match vimOper "\(\" skipwhite nextgroup=vimString,vimSpecFile syn match vimOper "||\|&&\|[-+.!]" skipwhite nextgroup=vimString,vimSpecFile -syn region vimOperParen matchgroup=vimParenSep start="(" end=")" contains=@vimOperGroup +syn region vimOperParen matchgroup=vimParenSep start="(" end=")" contains=vimoperStar,@vimOperGroup syn region vimOperParen matchgroup=vimSep start="{" end="}" contains=@vimOperGroup nextgroup=vimVar,vimFuncVar if !exists("g:vimsyn_noerror") && !exists("g:vimsyn_noopererror") syn match vimOperError ")" @@ -265,7 +265,7 @@ syn match vimSpecFileMod "\(:[phtre]\)\+" contained " User-Specified Commands: {{{2 " ======================= -syn cluster vimUserCmdList contains=vimAddress,vimSyntax,vimHighlight,vimAutoCmd,vimCmplxRepeat,vimComment,vimCtrlChar,vimEscapeBrace,vimFunc,vimFuncName,vimFunction,vimFunctionError,vimIsCommand,vimMark,vimNotation,vimNumber,vimOper,vimRegion,vimRegister,vimLet,vimSet,vimSetEqual,vimSetString,vimSpecFile,vimString,vimSubst,vimSubstRep,vimSubstRange,vimSynLine +syn cluster vimUserCmdList contains=vimAddress,vimSyntax,vimHighlight,vimAutoCmd,vimCmplxRepeat,vimComment,vim9Comment,vimCtrlChar,vimEscapeBrace,vimFunc,vimFuncName,vimFunction,vimFunctionError,vimIsCommand,vimMark,vimNotation,vimNumber,vimOper,vimRegion,vimRegister,vimLet,vimSet,vimSetEqual,vimSetString,vimSpecFile,vimString,vimSubst,vimSubstRep,vimSubstRange,vimSynLine syn keyword vimUserCommand contained com[mand] syn match vimUserCmd "\.*$" contains=vimUserAttrb,vimUserAttrbError,vimUserCommand,@vimUserCmdList syn match vimUserAttrbError contained "-\a\+\ze\s" @@ -295,6 +295,12 @@ syn match vimComment excludenl +\s"[^\-:.%#=*].*$+lc=1 contains=@vimCommentGroup syn match vimComment +\!\\@]"+lc=1 skip=+\\\\\|\\" syn region vimString oneline keepend start=+[^a-zA-Z>!\\@]'+lc=1 end=+'+ syn region vimString oneline start=+=!+lc=1 skip=+\\\\\|\\!+ end=+!+ contains=@vimStringGroup syn region vimString oneline start="=+"lc=1 skip="\\\\\|\\+" end="+" contains=@vimStringGroup -syn region vimString oneline start="\s/\s*\A"lc=1 skip="\\\\\|\\+" end="/" contains=@vimStringGroup +"syn region vimString oneline start="\s/\s*\A"lc=1 skip="\\\\\|\\+" end="/" contains=@vimStringGroup syn match vimString contained +"[^"]*\\$+ skipnl nextgroup=vimStringCont syn match vimStringCont contained +\(\\\\\|.\)\{-}[^\\]"+ @@ -372,7 +378,7 @@ syn match vimCmplxRepeat '[^a-zA-Z_/\\()]q[0-9a-zA-Z"]\>'lc=1 syn match vimCmplxRepeat '@[0-9a-z".=@:]\ze\($\|[^a-zA-Z]\>\)' " Set command and associated set-options (vimOptions) with comment {{{2 -syn region vimSet matchgroup=vimCommand start="\<\%(setl\%[ocal]\|setg\%[lobal]\|se\%[t]\)\>" skip="\%(\\\\\)*\\." end="$" end="|" matchgroup=vimNotation end="<[cC][rR]>" keepend oneline contains=vimSetEqual,vimOption,vimErrSetting,vimComment,vimSetString,vimSetMod +syn region vimSet matchgroup=vimCommand start="\<\%(setl\%[ocal]\|setg\%[lobal]\|se\%[t]\)\>" skip="\%(\\\\\)*\\." end="$" end="|" matchgroup=vimNotation end="<[cC][rR]>" keepend oneline contains=vimSetEqual,vimOption,vimErrSetting,vimComment,vim9Comment,vimSetString,vimSetMod syn region vimSetEqual contained start="[=:]\|[-+^]=" skip="\\\\\|\\\s" end="[| \t]\|$"me=e-1 contains=vimCtrlChar,vimSetSep,vimNotation,vimEnvvar oneline syn region vimSetString contained start=+="+hs=s+1 skip=+\\\\\|\\"+ end=+"+ contains=vimCtrlChar syn match vimSetSep contained "[,:]" skipwhite nextgroup=vimCommand @@ -381,7 +387,7 @@ syn match vimSetMod contained "&vim\=\|[!&?<]\|all&" " Let: {{{2 " === syn keyword vimLet let unl[et] skipwhite nextgroup=vimVar,vimFuncVar,vimLetHereDoc -VimFoldh syn region vimLetHereDoc matchgroup=vimLetHereDocStart start='=<<\s\+\%(trim\>\)\=\s*\z(\L\S*\)' matchgroup=vimLetHereDocStop end='^\s*\z1\s*$' contains=vimComment +VimFoldh syn region vimLetHereDoc matchgroup=vimLetHereDocStart start='=<<\s\+\%(trim\>\)\=\s*\z(\L\S*\)' matchgroup=vimLetHereDocStop end='^\s*\z1\s*$' contains=vimComment,vim9Comment " Abbreviations: {{{2 " ============= @@ -427,7 +433,7 @@ syn match vimMenuPriority "\d\+\(\.\d\+\)*" contained skipwhite nextgroup=vimMen syn match vimMenuNameMore "\c\\\s\|\|\\\." contained nextgroup=vimMenuName,vimMenuNameMore contains=vimNotation syn match vimMenuMod contained "\c<\(script\|silent\)\+>" skipwhite contains=vimMapModKey,vimMapModErr nextgroup=@vimMenuList syn match vimMenuMap "\s" contained skipwhite nextgroup=vimMenuRhs -syn match vimMenuRhs ".*$" contained contains=vimString,vimComment,vimIsCommand +syn match vimMenuRhs ".*$" contained contains=vimString,vimComment,vim9Comment,vimIsCommand syn match vimMenuBang "!" contained skipwhite nextgroup=@vimMenuList " Angle-Bracket Notation: (tnx to Michael Geddes) {{{2 @@ -477,8 +483,8 @@ syn match vimSynContains contained "\" contains=vimCommand skipwhite nextgroup=vimSynType,vimComment -syn match vimAuSyntax contained "\s+sy\%[ntax]" contains=vimCommand skipwhite nextgroup=vimSynType,vimComment +syn match vimSyntax "\" contains=vimCommand skipwhite nextgroup=vimSynType,vimComment,vim9Comment +syn match vimAuSyntax contained "\s+sy\%[ntax]" contains=vimCommand skipwhite nextgroup=vimSynType,vimComment,vim9Comment syn cluster vimFuncBodyList add=vimSyntax " Syntax: case {{{2 @@ -515,7 +521,7 @@ syn match vimSynKeyOpt contained "\%#=1\<\(conceal\|contained\|transparent\|skip syn cluster vimFuncBodyList add=vimSynType " Syntax: match {{{2 -syn cluster vimSynMtchGroup contains=vimMtchComment,vimSynContains,vimSynError,vimSynMtchOpt,vimSynNextgroup,vimSynRegPat,vimNotation +syn cluster vimSynMtchGroup contains=vimMtchComment,vimSynContains,vimSynError,vimSynMtchOpt,vimSynNextgroup,vimSynRegPat,vimNotation,vim9Comment syn keyword vimSynType contained match skipwhite nextgroup=vimSynMatchRegion syn region vimSynMatchRegion contained keepend matchgroup=vimGroupName start="\h\w*" matchgroup=vimSep end="|\|$" contains=@vimSynMtchGroup syn match vimSynMtchOpt contained "\%#=1\<\(conceal\|transparent\|contained\|excludenl\|keepend\|skipempty\|skipwhite\|display\|extend\|skipnl\|fold\)\>" @@ -569,7 +575,7 @@ syn match vimIsCommand "\s*\a\+" transparent contains=vimCommand,vimNotatio " Highlighting: {{{2 " ============ -syn cluster vimHighlightCluster contains=vimHiLink,vimHiClear,vimHiKeyList,vimComment +syn cluster vimHighlightCluster contains=vimHiLink,vimHiClear,vimHiKeyList,vimComment,vim9Comment if !exists("g:vimsyn_noerror") && !exists("g:vimsyn_novimhictermerror") syn match vimHiCtermError contained "\D\i*" endif @@ -624,6 +630,7 @@ syn match vimCtrlChar "[- -]" " Beginners - Patterns that involve ^ {{{2 " ========= syn match vimLineComment +^[ \t:]*".*$+ contains=@vimCommentGroup,vimCommentString,vimCommentTitle +syn match vim9LineComment +^[ \t:]\+#.*$+ contains=@vimCommentGroup,vimCommentString,vimCommentTitle syn match vimCommentTitle '"\s*\%([sS]:\|\h\w*#\)\=\u\w*\(\s\+\u\w*\)*:'hs=s+1 contained contains=vimCommentTitleLeader,vimTodo,@vimCommentGroup syn match vimContinue "^\s*\\" syn region vimString start="^\s*\\\z(['"]\)" skip='\\\\\|\\\z1' end="\z1" oneline keepend contains=@vimStringGroup,vimContinue @@ -738,10 +745,10 @@ if g:vimsyn_embed =~# 'P' && has("pythonx") && filereadable(s:pythonpath) unlet! b:current_syntax syn cluster vimFuncBodyList add=vimPythonRegion exe "syn include @vimPythonScript ".s:pythonpath - VimFoldP syn region vimPythonRegion matchgroup=vimScriptDelim start=+py\%[thon]3\=\s*<<\s*\z(\S*\)\ze\(\s*#.*\)\=$+ end=+^\z1\ze\(\s*".*\)\=$+ contains=@vimPythonScript - VimFoldP syn region vimPythonRegion matchgroup=vimScriptDelim start=+py\%[thon]3\=\s*<<\s*$+ end=+\.$+ contains=@vimPythonScript + VimFoldP syn region vimPythonRegion matchgroup=vimScriptDelim start=+py\%[thon][3x]\=\s*<<\s*\z(\S*\)\ze\(\s*#.*\)\=$+ end=+^\z1\ze\(\s*".*\)\=$+ contains=@vimPythonScript + VimFoldP syn region vimPythonRegion matchgroup=vimScriptDelim start=+py\%[thon][3x]\=\s*<<\s*$+ end=+\.$+ contains=@vimPythonScript VimFoldP syn region vimPythonRegion matchgroup=vimScriptDelim start=+Py\%[thon]2or3\s*<<\s*\z(\S*\)\ze\(\s*#.*\)\=$+ end=+^\z1\ze\(\s*".*\)\=$+ contains=@vimPythonScript - VimFoldP syn region vimPythonRegion matchgroup=vimScriptDelim start=+Py\%[thon]2or3\=\s*<<\s*$+ end=+\.$+ contains=@vimPythonScript + VimFoldP syn region vimPythonRegion matchgroup=vimScriptDelim start=+Py\%[thon]2or3\=\s*<<\s*$+ end=+\.$+ contains=@vimPythonScript syn cluster vimFuncBodyList add=vimPythonRegion else syn region vimEmbedError start=+py\%[thon]3\=\s*<<\s*\z(.*\)$+ end=+^\z1$+ @@ -857,6 +864,7 @@ if !exists("skip_vim_syntax_inits") hi def link vimCmplxRepeat SpecialChar hi def link vimCommand Statement hi def link vimComment Comment + hi def link vim9Comment Comment hi def link vimCommentString vimString hi def link vimCommentTitle PreProc hi def link vimCondHL vimCommand @@ -906,6 +914,7 @@ if !exists("skip_vim_syntax_inits") hi def link vimLetHereDocStart Special hi def link vimLetHereDocStop Special hi def link vimLineComment vimComment + hi def link vim9LineComment vimComment hi def link vimMapBang vimCommand hi def link vimMapModKey vimFuncSID hi def link vimMapMod vimBracket @@ -923,6 +932,7 @@ if !exists("skip_vim_syntax_inits") hi def link vimNumber Number hi def link vimOperError Error hi def link vimOper Operator + hi def link vimOperStar vimOper hi def link vimOption PreProc hi def link vimParenSep Delimiter hi def link vimPatSepErr vimError diff --git a/src/Make_all.mak b/src/Make_all.mak index 591350f413..6a6d2fe14e 100644 --- a/src/Make_all.mak +++ b/src/Make_all.mak @@ -5,6 +5,7 @@ # Argument for running ctags. TAGS_FILES = \ *.c \ + *.cc \ *.cpp \ *.h \ auto/*.c \ diff --git a/src/Make_cyg_ming.mak b/src/Make_cyg_ming.mak index 750e940e06..517ed2bfbc 100644 --- a/src/Make_cyg_ming.mak +++ b/src/Make_cyg_ming.mak @@ -787,6 +787,8 @@ OBJ = \ $(OUTDIR)/tag.o \ $(OUTDIR)/term.o \ $(OUTDIR)/testing.o \ + $(OUTDIR)/textformat.o \ + $(OUTDIR)/textobject.o \ $(OUTDIR)/textprop.o \ $(OUTDIR)/time.o \ $(OUTDIR)/ui.o \ @@ -1244,6 +1246,7 @@ $(OUTDIR)/pathdef.o: $(PATHDEF_SRC) $(INCL) CCCTERM = $(CC) -c $(CFLAGS) -Ilibvterm/include -DINLINE="" \ -DVSNPRINTF=vim_vsnprintf \ + -DSNPRINTF=vim_snprintf \ -DIS_COMBINING_FUNCTION=utf_iscomposing_uint \ -DWCWIDTH_FUNCTION=utf_uint2cells \ -DGET_SPECIAL_PTY_TYPE_FUNCTION=get_special_pty_type diff --git a/src/Make_morph.mak b/src/Make_morph.mak index 1830d85b50..43414e72cf 100644 --- a/src/Make_morph.mak +++ b/src/Make_morph.mak @@ -103,6 +103,8 @@ SRC = arabic.c \ tag.c \ term.c \ testing.c \ + textformat.c \ + textobject.c \ textprop.c \ time.c \ ui.c \ diff --git a/src/Make_mvc.mak b/src/Make_mvc.mak index ebc059f862..8240f50568 100644 --- a/src/Make_mvc.mak +++ b/src/Make_mvc.mak @@ -675,9 +675,6 @@ CFLAGS = $(CFLAGS) $(WP64CHECK) CFLAGS = $(CFLAGS) $(OPTFLAG) -DNDEBUG $(CPUARG) RCFLAGS = $(rcflags) $(rcvars) -DNDEBUG -! if "$(CL)" == "/D_USING_V110_SDK71_" -RCFLAGS = $(RCFLAGS) /D_USING_V110_SDK71_ -! endif ! ifdef USE_MSVCRT CFLAGS = $(CFLAGS) /MD LIBC = msvcrt.lib @@ -707,6 +704,10 @@ CFLAGS = $(CFLAGS) /Zl /MTd ! endif !endif # DEBUG +!if "$(CL)" == "/D_USING_V110_SDK71_" +RCFLAGS = $(RCFLAGS) /D_USING_V110_SDK71_ +!endif + !if $(MSVC_MAJOR) >= 8 # Visual Studio 2005 has 'deprecated' many of the standard CRT functions CFLAGS_DEPR = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE @@ -806,6 +807,8 @@ OBJ = \ $(OUTDIR)\tag.obj \ $(OUTDIR)\term.obj \ $(OUTDIR)\testing.obj \ + $(OUTDIR)\textformat.obj \ + $(OUTDIR)\textobject.obj \ $(OUTDIR)\textprop.obj \ $(OUTDIR)\time.obj \ $(OUTDIR)\ui.obj \ @@ -1744,6 +1747,10 @@ $(OUTDIR)/term.obj: $(OUTDIR) term.c $(INCL) $(OUTDIR)/term.obj: $(OUTDIR) testing.c $(INCL) +$(OUTDIR)/textformat.obj: $(OUTDIR) textformat.c $(INCL) + +$(OUTDIR)/textobject.obj: $(OUTDIR) textobject.c $(INCL) + $(OUTDIR)/textprop.obj: $(OUTDIR) textprop.c $(INCL) $(OUTDIR)/time.obj: $(OUTDIR) time.c $(INCL) @@ -1805,6 +1812,7 @@ $(OUTDIR)/glbl_ime.obj: $(OUTDIR) glbl_ime.cpp dimm.h $(INCL) CCCTERM = $(CC) $(CFLAGS) -Ilibvterm/include -DINLINE="" \ -DVSNPRINTF=vim_vsnprintf \ + -DSNPRINTF=vim_snprintf \ -DIS_COMBINING_FUNCTION=utf_iscomposing_uint \ -DWCWIDTH_FUNCTION=utf_uint2cells \ -DGET_SPECIAL_PTY_TYPE_FUNCTION=get_special_pty_type \ @@ -1942,6 +1950,8 @@ proto.h: \ proto/tag.pro \ proto/term.pro \ proto/testing.pro \ + proto/textformat.pro \ + proto/textobject.pro \ proto/textprop.pro \ proto/time.pro \ proto/ui.pro \ diff --git a/src/Make_vms.mms b/src/Make_vms.mms index fdd7ba7c1e..954d50a14f 100644 --- a/src/Make_vms.mms +++ b/src/Make_vms.mms @@ -382,6 +382,8 @@ SRC = \ term.c \ termlib.c \ testing.c \ + textformat.c \ + textobject.c \ textprop.c \ time.c \ ui.c \ @@ -491,6 +493,8 @@ OBJ = \ term.obj \ termlib.obj \ testing.obj \ + textformat.obj \ + textobject.obj \ textprop.obj \ time.obj \ ui.obj \ @@ -989,6 +993,12 @@ termlib.obj : termlib.c vim.h [.auto]config.h feature.h os_unix.h \ testing.obj : testing.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 +textformat.obj : textformat.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 +textobject.obj : textobject.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 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 diff --git a/src/Makefile b/src/Makefile index 24c69342cf..c3614fc8a7 100644 --- a/src/Makefile +++ b/src/Makefile @@ -618,7 +618,7 @@ CClink = $(CC) # 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 +#CFLAGS = -g -O2 -Wall -Wextra -Wshadow -Wmissing-prototypes -Wpedantic -Wunreachable-code -Wno-cast-function-type -Wunused-result -Wno-deprecated-declarations -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 #PYTHON_CFLAGS_EXTRA = -Wno-missing-field-initializers #MZSCHEME_CFLAGS_EXTRA = -Wno-unreachable-code -Wno-unused-parameter @@ -686,8 +686,10 @@ LINT_OPTIONS = -beprxzF # 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 +# PROFILE_CFLAGS=-g -O0 -fprofile-arcs -ftest-coverage -DWE_ARE_PROFILING -DUSE_GCOV_FLUSH +# Alternate flags +# PROFILE_CFLAGS=-g -O0 --coverage -DWE_ARE_PROFILING -DUSE_GCOV_FLUSH # Uncomment one of the next two lines to compile Vim with the @@ -696,7 +698,8 @@ LINT_OPTIONS = -beprxzF # More at: https://code.google.com/p/address-sanitizer/ # Useful environment variables: # $ export ASAN_OPTIONS="print_stacktrace=1 log_path=asan" -# $ export LSAN_OPTIONS="suppressions=$cwd/testdir/lsan-suppress.txt" +# $ export LSAN_OPTIONS="suppressions=`pwd`/testdir/lsan-suppress.txt" +# When running tests output can be found in testdir/asan.* #SANITIZER_CFLAGS = -g -O0 -fsanitize=address -fno-omit-frame-pointer #SANITIZER_CFLAGS = -g -O0 -fsanitize=undefined -fno-omit-frame-pointer SANITIZER_LIBS = $(SANITIZER_CFLAGS) @@ -1420,8 +1423,8 @@ MACVIMGUI_BUNDLE = macvim MACVIMGUI_TESTARG = VIMPROG=../$(RELEASEDIR)/MacVim.app/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 +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 gui_haiku.cc +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 gui_haiku.pro # }}} @@ -1696,6 +1699,8 @@ BASIC_SRC = \ term.c \ terminal.c \ testing.c \ + textformat.c \ + textobject.c \ textprop.c \ time.c \ ui.c \ @@ -1838,6 +1843,8 @@ OBJ_COMMON = \ objects/term.o \ objects/terminal.o \ objects/testing.o \ + objects/textformat.o \ + objects/textobject.o \ objects/textprop.o \ objects/time.o \ objects/ui.o \ @@ -2012,6 +2019,8 @@ PRO_AUTO = \ terminal.pro \ termlib.pro \ testing.pro \ + textformat.pro \ + textobject.pro \ textprop.pro \ time.pro \ ui.pro \ @@ -2304,7 +2313,6 @@ test_libvterm: # Run individual OLD style test. # These do not depend on the executable, compile it when needed. test1 \ - test_eval \ test42 test44 test49 \ test52 test59 \ test70 \ @@ -2899,7 +2907,7 @@ uninstall_runtime: clean celan: testclean macvimclean -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 $(TOOLS) auto/osdef.h auto/pathdef.c auto/if_perl.c auto/gui_gtk_gresources.c auto/gui_gtk_gresources.h auto/os_haiku.rdef -rm -f conftest* *~ auto/link.sed -rm -f testdir/opt_test.vim -rm -f $(UNITTEST_TARGETS) @@ -2932,7 +2940,7 @@ clean celan: testclean macvimclean # % make SHADOWDIR = shadow -LINKEDFILES = ../*.[chm] ../*.in ../*.sh ../*.xs ../*.xbm ../gui_gtk_res.xml ../toolcheck ../proto ../libvterm ../vimtutor ../gvimtutor ../install-sh ../Make_all.mak +LINKEDFILES = ../*.[chm] ../*.cc ../*.in ../*.sh ../*.xs ../*.xbm ../gui_gtk_res.xml ../toolcheck ../proto ../libvterm ../vimtutor ../gvimtutor ../install-sh ../Make_all.mak shadow: runtime pixmaps $(MKDIR_P) $(SHADOWDIR) @@ -3056,6 +3064,14 @@ auto/if_perl.c: 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/os_haiku.rdef: os_haiku.rdef.in + @echo creating $@ + @echo '/* This file is automatically created by Makefile */' >> $@ + @echo '/* DO NOT EDIT! Change Makefile only. */' >> $@ + @cat $(srcdir)/os_haiku.rdef.in >> auto/os_haiku.rdef + sed -i "s|@MAJOR@|$(VIMMAJOR)|" auto/os_haiku.rdef + sed -i "s|@MINOR@|$(VIMMINOR)|" auto/os_haiku.rdef + auto/pathdef.c: Makefile auto/config.mk -@echo creating $@ -@echo '/* pathdef.c */' > $@ @@ -3407,7 +3423,7 @@ objects/os_beos.o: os_beos.c objects/os_qnx.o: os_qnx.c $(CCC) -o $@ os_qnx.c -objects/os_haiku.rsrc: os_haiku.rdef +objects/os_haiku.rsrc: auto/os_haiku.rdef cat $< | $(CCC) -E - | grep -v '^#' | rc -o "$@" - objects/os_macosx.o: os_macosx.m @@ -3494,6 +3510,12 @@ objects/terminal.o: terminal.c $(TERM_DEPS) objects/testing.o: testing.c $(CCC) -o $@ testing.c +objects/textformat.o: textformat.c + $(CCC) -o $@ textformat.c + +objects/textobject.o: textobject.c + $(CCC) -o $@ textobject.c + objects/textprop.o: textprop.c $(CCC) -o $@ textprop.c @@ -3541,6 +3563,7 @@ Makefile: # prefix vterm_ to avoid name clashes. CCCTERM = $(CCC_NF) $(VTERM_CFLAGS) $(ALL_CFLAGS) -DINLINE="" \ -DVSNPRINTF=vim_vsnprintf \ + -DSNPRINTF=vim_snprintf \ -DIS_COMBINING_FUNCTION=utf_iscomposing_uint \ -DWCWIDTH_FUNCTION=utf_uint2cells @@ -3565,7 +3588,7 @@ objects/vterm_screen.o: libvterm/src/screen.c $(TERM_DEPS) objects/vterm_state.o: libvterm/src/state.c $(TERM_DEPS) $(CCCTERM) -o $@ libvterm/src/state.c -objects/vterm_unicode.o: libvterm/src/unicode.c $(TERM_DEPS) +objects/vterm_unicode.o: libvterm/src/unicode.c $(TERM_DEPS) libvterm/src/fullwidth.inc $(CCCTERM) -o $@ libvterm/src/unicode.c objects/vterm_vterm.o: libvterm/src/vterm.c $(TERM_DEPS) @@ -4128,6 +4151,14 @@ objects/testing.o: testing.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 +objects/textformat.o: textformat.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 +objects/textobject.o: textobject.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 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 \ diff --git a/src/README.md b/src/README.md index 54be08284f..624bd6a829 100644 --- a/src/README.md +++ b/src/README.md @@ -80,6 +80,8 @@ syntax.c | syntax and other highlighting tag.c | tags term.c | terminal handling, termcap codes testing.c | testing: assert and test functions +textformat.c | text formatting +textobject.c | text objects textprop.c | text properties time.c | time and timer functions undo.c | undo and redo diff --git a/src/auto/configure b/src/auto/configure index 78f6ee6781..c83a20ee35 100755 --- a/src/auto/configure +++ b/src/auto/configure @@ -5543,7 +5543,7 @@ $as_echo "no" >&6; } # https://groups.google.com/forum/#!topic/vim_use/O0vek60WuTk lua_suf=/moonjit-2.3 inc_path="$vi_cv_path_lua_pfx/include" - for dir in "$inc_path"/moonjit-0-9* ; do + for dir in "$inc_path"/moonjit-[0-9]* ; do if test -d "$dir" ; then lua_suf=`basename '$dir'` lua_suf="/$lua_suf" @@ -12609,103 +12609,6 @@ else $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 -#if STDC_HEADERS -# include -# include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -#include -#include -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; } @@ -14053,6 +13956,53 @@ fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dirfd" >&5 +$as_echo_n "checking for dirfd... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +int +main () +{ +DIR * dir=opendir("dirname"); dirfd(dir); + ; + 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_DIRFD 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 flock" >&5 +$as_echo_n "checking for flock... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +flock(10, LOCK_SH); + ; + 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_FLOCK 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 sysctl" >&5 $as_echo_n "checking for sysctl... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext diff --git a/src/beval.c b/src/beval.c index 6b10a654d8..b7d9226e70 100644 --- a/src/beval.c +++ b/src/beval.c @@ -282,7 +282,7 @@ general_beval_cb(BalloonEval *beval, int state UNUSED) curbuf = save_curbuf; if (use_sandbox) ++sandbox; - ++textlock; + ++textwinlock; vim_free(result); result = eval_to_string(bexpr, NULL, TRUE); @@ -299,7 +299,7 @@ general_beval_cb(BalloonEval *beval, int state UNUSED) if (use_sandbox) --sandbox; - --textlock; + --textwinlock; set_vim_var_string(VV_BEVAL_TEXT, NULL, -1); if (result != NULL && result[0] != NUL) diff --git a/src/beval.h b/src/beval.h index 1bee3e9519..c1cfff7838 100644 --- a/src/beval.h +++ b/src/beval.h @@ -83,6 +83,10 @@ typedef struct BalloonEvalStruct #ifdef FEAT_GUI_MSWIN void *tofree; #endif +#ifdef FEAT_GUI_HAIKU + int x; + int y; +#endif } BalloonEval; #define EVAL_OFFSET_X 15 // displacement of beval topleft corner from pointer diff --git a/src/change.c b/src/change.c index 1123c19b41..f3a3fb9847 100644 --- a/src/change.c +++ b/src/change.c @@ -382,7 +382,7 @@ invoke_listeners(buf_T *buf) argv[4].v_type = VAR_LIST; argv[4].vval.v_list = buf->b_recorded_changes; - ++textlock; + ++textwinlock; for (lnr = buf->b_listener; lnr != NULL; lnr = lnr->lr_next) { @@ -390,7 +390,7 @@ invoke_listeners(buf_T *buf) clear_tv(&rettv); } - --textlock; + --textwinlock; list_unref(buf->b_recorded_changes); buf->b_recorded_changes = NULL; diff --git a/src/channel.c b/src/channel.c index 66c313fd90..c291a5dee8 100644 --- a/src/channel.c +++ b/src/channel.c @@ -156,9 +156,9 @@ ch_logfile(char_u *fname, char_u *opt) if (log_fd != NULL) { if (*fname != NUL) - ch_log(NULL, "closing, opening %s", fname); + ch_log(NULL, "closing this logfile, opening %s", fname); else - ch_log(NULL, "closing"); + ch_log(NULL, "closing logfile"); fclose(log_fd); } @@ -974,6 +974,7 @@ channel_open( int sd = -1; channel_T *channel = NULL; #ifdef FEAT_IPV6 + int err; struct addrinfo hints; struct addrinfo *res = NULL; struct addrinfo *addr = NULL; @@ -1005,10 +1006,11 @@ channel_open( // Set port number manually in order to prevent name resolution services // from being invoked in the environment where AI_NUMERICSERV is not // defined. - if (getaddrinfo(hostname, NULL, &hints, &res) != 0) + if ((err = getaddrinfo(hostname, NULL, &hints, &res)) != 0) { ch_error(channel, "in getaddrinfo() in channel_open()"); - PERROR(_("E901: getaddrinfo() in channel_open()")); + semsg(_("E901: getaddrinfo() in channel_open(): %s"), + gai_strerror(err)); channel_free(channel); return NULL; } @@ -1054,7 +1056,7 @@ channel_open( if (waittime == 0) waittime = 1; - sd = channel_connect(channel, addr->ai_addr, addr->ai_addrlen, + sd = channel_connect(channel, addr->ai_addr, (int)addr->ai_addrlen, &waittime); if (sd >= 0) break; @@ -2423,7 +2425,7 @@ channel_get_json( list_T *l = item->jq_value->vval.v_list; typval_T *tv; - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); tv = &l->lv_first->li_tv; if ((without_callback || !item->jq_no_callback) @@ -3964,7 +3966,7 @@ theend: free_job_options(&opt); } -# ifdef FEAT_GUI_MACVIM +#ifdef FEAT_GUI_MACVIM /* * Read from channel "channel" in dispatch event handler. * Channel may be already read out elsewhere before the handler invoked @@ -3978,9 +3980,9 @@ channel_may_read(channel_T *channel, ch_part_T part, char *func) if (fd != INVALID_FD && channel_wait(channel, fd, 0) == CW_READY) channel_read(channel, part, func); } -# endif +#endif -# if defined(MSWIN) || defined(FEAT_GUI) || defined(PROTO) +#if defined(MSWIN) || defined(__HAIKU__) || defined(FEAT_GUI) || defined(PROTO) /* * Check the channels for anything that is ready to be read. * The data is put in the read queue. @@ -4013,9 +4015,23 @@ channel_handle_events(int only_keep_open) "channel_handle_events"); } } + +# ifdef __HAIKU__ + // Workaround for Haiku: Since select/poll cannot detect EOF from tty, + // should close fds when the job has finished if 'channel' connects to + // the pty. + if (channel->ch_job != NULL) + { + job_T *job = channel->ch_job; + + if (job->jv_tty_out != NULL && job->jv_status == JOB_FINISHED) + for (part = PART_SOCK; part < PART_COUNT; ++part) + ch_close_part(channel, part); + } +# endif } } -# endif +#endif # if defined(FEAT_GUI) || defined(PROTO) /* @@ -4581,6 +4597,20 @@ channel_select_check(int ret_in, void *rfds_in, void *wfds_in) channel_write_input(channel); --ret; } + +# ifdef __HAIKU__ + // Workaround for Haiku: Since select/poll cannot detect EOF from tty, + // should close fds when the job has finished if 'channel' connects to + // the pty. + if (channel->ch_job != NULL) + { + job_T *job = channel->ch_job; + + if (job->jv_tty_out != NULL && job->jv_status == JOB_FINISHED) + for (part = PART_SOCK; part < PART_COUNT; ++part) + ch_close_part(channel, part); + } +# endif } return ret; @@ -5314,12 +5344,13 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2) return FAIL; } - range_list_materialize(item->vval.v_list); + CHECK_LIST_MATERIALIZE(item->vval.v_list); li = item->vval.v_list->lv_first; for (; li != NULL && n < 16; li = li->li_next, n++) { char_u *color_name; guicolor_T guicolor; + int called_emsg_before = called_emsg; color_name = tv_get_string_chk(&li->li_tv); if (color_name == NULL) @@ -5327,7 +5358,12 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2) guicolor = GUI_GET_COLOR(color_name); if (guicolor == INVALCOLOR) + { + if (called_emsg_before == called_emsg) + // may not get the error if the GUI didn't start + semsg(_(e_alloc_color), color_name); return FAIL; + } rgb[n] = GUI_MCH_GET_RGB(guicolor); } @@ -5741,7 +5777,7 @@ win32_build_cmd(list_T *l, garray_T *gap) listitem_T *li; char_u *s; - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); FOR_ALL_LIST_ITEMS(l, li) { s = tv_get_string_chk(&li->li_tv); diff --git a/src/clientserver.c b/src/clientserver.c index 9611d590b8..33e14bb876 100644 --- a/src/clientserver.c +++ b/src/clientserver.c @@ -478,6 +478,7 @@ cmdsrv_main( # ifdef FEAT_GUI_MSWIN Shell_NotifyIcon(NIM_DELETE, &ni); # endif + vim_free(done); } } else if (STRICMP(argv[i], "--remote-expr") == 0) diff --git a/src/config.h.in b/src/config.h.in index 83549303f6..5c8c7e5561 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -126,12 +126,6 @@ #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 @@ -490,5 +484,11 @@ /* Define if we have isnan() */ #undef HAVE_ISNAN +/* Define if we have dirfd() */ +#undef HAVE_DIRFD + +/* Define if we have flock() */ +#undef HAVE_FLOCK + /* Define to inline symbol or empty */ #undef inline diff --git a/src/configure.ac b/src/configure.ac index ea60d597e0..cc07980765 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -662,7 +662,7 @@ if test "$enable_luainterp" = "yes" -o "$enable_luainterp" = "dynamic"; then # https://groups.google.com/forum/#!topic/vim_use/O0vek60WuTk lua_suf=/moonjit-2.3 inc_path="$vi_cv_path_lua_pfx/include" - for dir in "$inc_path"/moonjit-[0-9]* ; do + for dir in "$inc_path"/moonjit-[[0-9]]* ; do if test -d "$dir" ; then lua_suf=`basename '$dir'` lua_suf="/$lua_suf" @@ -3771,77 +3771,6 @@ else AC_MSG_RESULT([don't know]) fi -dnl **** pty mode/group handling **** -dnl -dnl support provided by Luke Mewburn , 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 -#if STDC_HEADERS -# include -# include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -#include -#include -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 @@ -4229,6 +4158,21 @@ AC_TRY_LINK([#include ], [rename("this", "that")], AC_MSG_RESULT(yes); AC_DEFINE(HAVE_RENAME), AC_MSG_RESULT(no)) +dnl check for dirfd() +AC_MSG_CHECKING(for dirfd) +AC_TRY_COMPILE( +[#include +#include ], +[DIR * dir=opendir("dirname"); dirfd(dir);], +AC_MSG_RESULT(yes); AC_DEFINE(HAVE_DIRFD), AC_MSG_RESULT(not usable)) + +dnl check for flock() +AC_MSG_CHECKING(for flock) +AC_TRY_COMPILE( +[#include ], +[flock(10, LOCK_SH);], +AC_MSG_RESULT(yes); AC_DEFINE(HAVE_FLOCK), AC_MSG_RESULT(not usable)) + dnl sysctl() may exist but not the arguments we use AC_MSG_CHECKING(for sysctl) AC_TRY_COMPILE( diff --git a/src/dict.c b/src/dict.c index 1a928a35f2..3824f407cb 100644 --- a/src/dict.c +++ b/src/dict.c @@ -104,29 +104,38 @@ rettv_dict_set(typval_T *rettv, dict_T *d) */ void dict_free_contents(dict_T *d) +{ + hashtab_free_contents(&d->dv_hashtab); +} + +/* + * Clear hashtab "ht" and dict items it contains. + */ + void +hashtab_free_contents(hashtab_T *ht) { 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) + hash_lock(ht); + todo = (int)ht->ht_used; + for (hi = ht->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); + hash_remove(ht, hi); dictitem_free(di); --todo; } } - // The hashtab is still locked, it has to be re-initialized anyway - hash_clear(&d->dv_hashtab); + // The hashtab is still locked, it has to be re-initialized anyway. + hash_clear(ht); } static void @@ -782,8 +791,9 @@ get_literal_key(char_u **arg, typval_T *tv) * Return OK or FAIL. Returns NOTDONE for {expr}. */ int -eval_dict(char_u **arg, typval_T *rettv, int evaluate, int literal) +eval_dict(char_u **arg, typval_T *rettv, int flags, int literal) { + int evaluate = flags & EVAL_EVALUATE; dict_T *d = NULL; typval_T tvkey; typval_T tv; @@ -791,6 +801,7 @@ eval_dict(char_u **arg, typval_T *rettv, int evaluate, int literal) dictitem_T *item; char_u *start = skipwhite(*arg + 1); char_u buf[NUMBUFLEN]; + int vim9script = current_sctx.sc_version == SCRIPT_VERSION_VIM9; /* * First check if it's not a curly-braces thing: {expr}. @@ -799,9 +810,9 @@ eval_dict(char_u **arg, typval_T *rettv, int evaluate, int literal) * first item. * But {} is an empty Dictionary. */ - if (*start != '}') + if (!vim9script && *start != '}') { - if (eval1(&start, &tv, FALSE) == FAIL) // recursive! + if (eval1(&start, &tv, 0) == FAIL) // recursive! return FAIL; if (*start == '}') return NOTDONE; @@ -821,7 +832,7 @@ eval_dict(char_u **arg, typval_T *rettv, int evaluate, int literal) { if ((literal ? get_literal_key(arg, &tvkey) - : eval1(arg, &tvkey, evaluate)) == FAIL) // recursive! + : eval1(arg, &tvkey, flags)) == FAIL) // recursive! goto failret; if (**arg != ':') @@ -843,7 +854,7 @@ eval_dict(char_u **arg, typval_T *rettv, int evaluate, int literal) } *arg = skipwhite(*arg + 1); - if (eval1(arg, &tv, evaluate) == FAIL) // recursive! + if (eval1(arg, &tv, flags) == FAIL) // recursive! { if (evaluate) clear_tv(&tvkey); @@ -977,14 +988,15 @@ dict_equal( 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; + if (dict_len(d1) == 0) + // empty and NULL dicts are considered equal + return TRUE; + if (d1 == NULL || d2 == NULL) + return FALSE; todo = (int)d1->dv_hashtab.ht_used; for (hi = d1->dv_hashtab.ht_array; todo > 0; ++hi) diff --git a/src/drawline.c b/src/drawline.c index 04490ad644..211d7680ab 100644 --- a/src/drawline.c +++ b/src/drawline.c @@ -1177,6 +1177,12 @@ win_line( c_final = NUL; n_extra = get_breakindent_win(wp, ml_get_buf(wp->w_buffer, lnum, FALSE)); + if (row == startrow) + { + n_extra -= win_col_off2(wp); + if (n_extra < 0) + n_extra = 0; + } if (wp->w_skipcol > 0 && wp->w_p_wrap && wp->w_briopt_sbr) need_showbreak = FALSE; // Correct end of highlighted area for 'breakindent', @@ -3099,9 +3105,9 @@ win_line( #ifdef FEAT_SYN_HL if (!(cul_screenline # ifdef FEAT_DIFF - && diff_hlf == (hlf_T)0) + && diff_hlf == (hlf_T)0 # endif - ) + )) saved_char_attr = char_attr; else #endif diff --git a/src/drawscreen.c b/src/drawscreen.c index 8f53a359aa..ea787e1a54 100644 --- a/src/drawscreen.c +++ b/src/drawscreen.c @@ -2439,7 +2439,8 @@ win_update(win_T *wp) #ifdef FEAT_VTP // Rewrite the character at the end of the screen line. - if (use_vtp()) + // See the version that was fixed. + if (use_vtp() && get_conpty_fix_type() < 1) { int i; diff --git a/src/edit.c b/src/edit.c index b880fec67f..836e658c9e 100644 --- a/src/edit.c +++ b/src/edit.c @@ -28,8 +28,6 @@ static void ins_ctrl_v(void); static void init_prompt(int cmdchar_todo); #endif 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_common(pos_T *end_insert_pos, int change); #ifdef FEAT_SPELL @@ -104,8 +102,6 @@ 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 key @@ -175,16 +171,11 @@ edit( #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; - } - // Don't allow recursive insert mode when busy with completion. - if (ins_compl_active() || compl_busy || pum_visible()) + if (textwinlock != 0 || textlock != 0 + || ins_compl_active() || compl_busy || pum_visible()) { - emsg(_(e_secure)); + emsg(_(e_textwinlock)); return FALSE; } ins_compl_clear(); // clear stuff for CTRL-X mode @@ -2077,8 +2068,6 @@ insert_special( # 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 @@ -2315,567 +2304,6 @@ insertchar( } } -/* - * 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; - colnr_T leader_len; - int no_leader = FALSE; - int do_comments = (flags & INSCHAR_DO_COM); -#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; - - 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; - if (!(flags & INSCHAR_FORMAT) - && leader_len == 0 - && !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; - - // Don't break until after the comment leader - if (curwin->w_cursor.col < leader_len) - break; - 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 - // do not break "#a b" when 'tw' is 2 - if (curwin->w_cursor.col <= leader_len) - break; - 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) - { - // Don't break until after the comment leader - if (curwin->w_cursor.col < leader_len) - break; - 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 - // Don't break until after the comment leader - if (curwin->w_cursor.col < leader_len) - break; - - 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) - + (do_comments ? OPENLINE_DO_COM : 0) - + ((flags & INSCHAR_COM_LIST) ? OPENLINE_COM_LIST : 0) - , ((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 - 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 - { - (void)set_indent(second_indent, SIN_CHANGED); - } - } - } - 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; - } - - // 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; - - /* - * 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. */ @@ -5959,7 +5387,7 @@ do_insert_char_pre(int c) } // Lock the text to avoid weird things from happening. - ++textlock; + ++textwinlock; set_vim_var_string(VV_CHAR, buf, -1); // set v:char res = NULL; @@ -5973,7 +5401,7 @@ do_insert_char_pre(int c) } set_vim_var_string(VV_CHAR, NULL, -1); // clear v:char - --textlock; + --textwinlock; // Restore the State, it may have been changed. State = save_State; @@ -6009,7 +5437,8 @@ ins_apply_autocmds(event_T event) // 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)) + // Except when leaving Insert mode. + if (event != EVENT_INSERTLEAVE && 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 index 94ecf936e4..87b7644251 100644 --- a/src/eval.c +++ b/src/eval.c @@ -34,8 +34,6 @@ static char *e_float_as_string = N_("E806: using Float as a String"); */ static int current_copyID = 0; -static int echo_attr = 0; // attributes used for ":echo" - /* * Info used by a ":for" loop. */ @@ -50,12 +48,12 @@ typedef struct } forinfo_T; static int tv_op(typval_T *tv1, typval_T *tv2, char_u *op); -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 eval2(char_u **arg, typval_T *rettv, int flags); +static int eval3(char_u **arg, typval_T *rettv, int flags); +static int eval4(char_u **arg, typval_T *rettv, int flags); +static int eval5(char_u **arg, typval_T *rettv, int flags); +static int eval6(char_u **arg, typval_T *rettv, int flags, int want_string); +static int eval7(char_u **arg, typval_T *rettv, int flags, int want_string); static int eval7_leader(typval_T *rettv, char_u *start_leader, char_u **end_leaderp); static int free_unref_items(int copyID); @@ -175,7 +173,7 @@ eval_to_bool( if (skip) ++emsg_skip; - if (eval0(arg, &tv, nextcmd, !skip) == FAIL) + if (eval0(arg, &tv, nextcmd, skip ? 0 : EVAL_EVALUATE) == FAIL) *error = TRUE; else { @@ -203,7 +201,7 @@ eval1_emsg(char_u **arg, typval_T *rettv, int evaluate) int did_emsg_before = did_emsg; int called_emsg_before = called_emsg; - ret = eval1(arg, rettv, evaluate); + ret = eval1(arg, rettv, evaluate ? EVAL_EVALUATE : 0); if (ret == FAIL) { // Report the invalid expression unless the expression evaluation has @@ -243,9 +241,14 @@ eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T *rettv) { partial_T *partial = expr->vval.v_partial; - if (partial->pt_func != NULL && partial->pt_func->uf_dfunc_idx >= 0) + if (partial == NULL) + return FAIL; + + if (partial->pt_func != NULL + && partial->pt_func->uf_dfunc_idx != UF_NOT_COMPILED) { - if (call_def_function(partial->pt_func, argc, argv, rettv) == FAIL) + if (call_def_function(partial->pt_func, argc, argv, + partial, rettv) == FAIL) return FAIL; } else @@ -314,7 +317,7 @@ eval_to_string_skip( if (skip) ++emsg_skip; - if (eval0(arg, &tv, nextcmd, !skip) == FAIL || skip) + if (eval0(arg, &tv, nextcmd, skip ? 0 : EVAL_EVALUATE) == FAIL || skip) retval = NULL; else { @@ -337,7 +340,7 @@ skip_expr(char_u **pp) typval_T rettv; *pp = skipwhite(*pp); - return eval1(pp, &rettv, FALSE); + return eval1(pp, &rettv, 0); } /* @@ -359,7 +362,7 @@ eval_to_string( char_u numbuf[NUMBUFLEN]; #endif - if (eval0(arg, &tv, nextcmd, TRUE) == FAIL) + if (eval0(arg, &tv, nextcmd, EVAL_EVALUATE) == FAIL) retval = NULL; else { @@ -392,7 +395,7 @@ eval_to_string( /* * Call eval_to_string() without using current local variables and using - * textlock. When "use_sandbox" is TRUE use the sandbox. + * textwinlock. When "use_sandbox" is TRUE use the sandbox. */ char_u * eval_to_string_safe( @@ -406,11 +409,11 @@ eval_to_string_safe( save_funccal(&funccal_entry); if (use_sandbox) ++sandbox; - ++textlock; + ++textwinlock; retval = eval_to_string(arg, nextcmd, FALSE); if (use_sandbox) --sandbox; - --textlock; + --textwinlock; restore_funccal(); return retval; } @@ -429,7 +432,7 @@ eval_to_number(char_u *expr) ++emsg_off; - if (eval1(&p, &rettv, TRUE) == FAIL) + if (eval1(&p, &rettv, EVAL_EVALUATE) == FAIL) retval = -1; else { @@ -452,7 +455,7 @@ eval_expr(char_u *arg, char_u **nextcmd) typval_T *tv; tv = ALLOC_ONE(typval_T); - if (tv != NULL && eval0(arg, tv, nextcmd, TRUE) == FAIL) + if (tv != NULL && eval0(arg, tv, nextcmd, EVAL_EVALUATE) == FAIL) VIM_CLEAR(tv); return tv; @@ -575,9 +578,9 @@ eval_foldexpr(char_u *arg, int *cp) ++emsg_off; if (use_sandbox) ++sandbox; - ++textlock; + ++textwinlock; *cp = NUL; - if (eval0(arg, &tv, NULL, TRUE) == FAIL) + if (eval0(arg, &tv, NULL, EVAL_EVALUATE) == FAIL) retval = 0; else { @@ -600,7 +603,7 @@ eval_foldexpr(char_u *arg, int *cp) --emsg_off; if (use_sandbox) --sandbox; - --textlock; + --textwinlock; return (int)retval; } @@ -765,7 +768,7 @@ get_lval( else { empty1 = FALSE; - if (eval1(&p, &var1, TRUE) == FAIL) // recursive! + if (eval1(&p, &var1, EVAL_EVALUATE) == FAIL) // recursive! return NULL; if (tv_get_string_chk(&var1) == NULL) { @@ -802,7 +805,8 @@ get_lval( else { lp->ll_empty2 = FALSE; - if (eval1(&p, &var2, TRUE) == FAIL) // recursive! + // recursive! + if (eval1(&p, &var2, EVAL_EVALUATE) == FAIL) { clear_tv(&var1); return NULL; @@ -871,7 +875,10 @@ get_lval( if (len != -1) key[len] = prevval; if (wrong) + { + clear_tv(&var1); return NULL; + } } if (lp->ll_di == NULL) @@ -1429,7 +1436,8 @@ eval_for_line( if (skip) ++emsg_skip; - if (eval0(skipwhite(expr + 2), &tv, nextcmdp, !skip) == OK) + if (eval0(skipwhite(expr + 2), &tv, nextcmdp, skip ? 0 : EVAL_EVALUATE) + == OK) { *errp = FALSE; if (!skip) @@ -1445,7 +1453,7 @@ eval_for_line( else { // Need a real list here. - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); // No need to increment the refcount, it's already set for // the list being used in "tv". @@ -1690,9 +1698,10 @@ eval_func( char_u *name, int name_len, typval_T *rettv, - int evaluate, + int flags, typval_T *basetv) // "expr" for "expr->name(arg)" { + int evaluate = flags & EVAL_EVALUATE; char_u *s = name; int len = name_len; partial_T *partial; @@ -1708,7 +1717,7 @@ eval_func( // Need to make a copy, in case evaluating the arguments makes // the name invalid. s = vim_strsave(s); - if (s == NULL) + if (s == NULL || (flags & EVAL_CONSTANT)) ret = FAIL; else { @@ -1757,6 +1766,7 @@ eval_func( * 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. + * "flags" has EVAL_EVALUATE and similar flags. * Return OK or FAIL. */ int @@ -1764,7 +1774,7 @@ eval0( char_u *arg, typval_T *rettv, char_u **nextcmd, - int evaluate) + int flags) { int ret; char_u *p; @@ -1772,8 +1782,8 @@ eval0( int called_emsg_before = called_emsg; p = skipwhite(arg); - ret = eval1(&p, rettv, evaluate); - if (ret == FAIL || !ends_excmd(*p)) + ret = eval1(&p, rettv, flags); + if (ret == FAIL || !ends_excmd2(arg, p)) { if (ret != FAIL) clear_tv(rettv); @@ -1783,8 +1793,10 @@ eval0( * 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) + if (!aborting() + && did_emsg == did_emsg_before + && called_emsg == called_emsg_before + && (flags & EVAL_CONSTANT) == 0) semsg(_(e_invexpr2), arg); ret = FAIL; } @@ -1806,7 +1818,7 @@ eval0( * Return OK or FAIL. */ int -eval1(char_u **arg, typval_T *rettv, int evaluate) +eval1(char_u **arg, typval_T *rettv, int flags) { int result; typval_T var2; @@ -1814,13 +1826,15 @@ eval1(char_u **arg, typval_T *rettv, int evaluate) /* * Get the first variable. */ - if (eval2(arg, rettv, evaluate) == FAIL) + if (eval2(arg, rettv, flags) == FAIL) return FAIL; if ((*arg)[0] == '?') { + int evaluate = flags & EVAL_EVALUATE; + result = FALSE; - if (evaluate) + if (flags & EVAL_EVALUATE) { int error = FALSE; @@ -1832,10 +1846,10 @@ eval1(char_u **arg, typval_T *rettv, int evaluate) } /* - * Get the second variable. + * Get the second variable. Recursive! */ *arg = skipwhite(*arg + 1); - if (eval1(arg, rettv, evaluate && result) == FAIL) // recursive! + if (eval1(arg, rettv, result ? flags : flags & ~EVAL_EVALUATE) == FAIL) return FAIL; /* @@ -1850,10 +1864,10 @@ eval1(char_u **arg, typval_T *rettv, int evaluate) } /* - * Get the third variable. + * Get the third variable. Recursive! */ *arg = skipwhite(*arg + 1); - if (eval1(arg, &var2, evaluate && !result) == FAIL) // recursive! + if (eval1(arg, &var2, !result ? flags : flags & ~EVAL_EVALUATE) == FAIL) { if (evaluate && result) clear_tv(rettv); @@ -1876,7 +1890,7 @@ eval1(char_u **arg, typval_T *rettv, int evaluate) * Return OK or FAIL. */ static int -eval2(char_u **arg, typval_T *rettv, int evaluate) +eval2(char_u **arg, typval_T *rettv, int flags) { typval_T var2; long result; @@ -1886,7 +1900,7 @@ eval2(char_u **arg, typval_T *rettv, int evaluate) /* * Get the first variable. */ - if (eval3(arg, rettv, evaluate) == FAIL) + if (eval3(arg, rettv, flags) == FAIL) return FAIL; /* @@ -1896,6 +1910,8 @@ eval2(char_u **arg, typval_T *rettv, int evaluate) result = FALSE; while ((*arg)[0] == '|' && (*arg)[1] == '|') { + int evaluate = flags & EVAL_EVALUATE; + if (evaluate && first) { if (tv_get_number_chk(rettv, &error) != 0) @@ -1910,7 +1926,8 @@ eval2(char_u **arg, typval_T *rettv, int evaluate) * Get the second variable. */ *arg = skipwhite(*arg + 2); - if (eval3(arg, &var2, evaluate && !result) == FAIL) + if (eval3(arg, &var2, !result ? flags : flags & ~EVAL_EVALUATE) + == FAIL) return FAIL; /* @@ -1944,7 +1961,7 @@ eval2(char_u **arg, typval_T *rettv, int evaluate) * Return OK or FAIL. */ static int -eval3(char_u **arg, typval_T *rettv, int evaluate) +eval3(char_u **arg, typval_T *rettv, int flags) { typval_T var2; long result; @@ -1954,7 +1971,7 @@ eval3(char_u **arg, typval_T *rettv, int evaluate) /* * Get the first variable. */ - if (eval4(arg, rettv, evaluate) == FAIL) + if (eval4(arg, rettv, flags) == FAIL) return FAIL; /* @@ -1964,6 +1981,8 @@ eval3(char_u **arg, typval_T *rettv, int evaluate) result = TRUE; while ((*arg)[0] == '&' && (*arg)[1] == '&') { + int evaluate = flags & EVAL_EVALUATE; + if (evaluate && first) { if (tv_get_number_chk(rettv, &error) == 0) @@ -1978,7 +1997,7 @@ eval3(char_u **arg, typval_T *rettv, int evaluate) * Get the second variable. */ *arg = skipwhite(*arg + 2); - if (eval4(arg, &var2, evaluate && result) == FAIL) + if (eval4(arg, &var2, result ? flags : flags & ~EVAL_EVALUATE) == FAIL) return FAIL; /* @@ -2021,7 +2040,7 @@ eval3(char_u **arg, typval_T *rettv, int evaluate) * Return OK or FAIL. */ static int -eval4(char_u **arg, typval_T *rettv, int evaluate) +eval4(char_u **arg, typval_T *rettv, int flags) { typval_T var2; char_u *p; @@ -2033,7 +2052,7 @@ eval4(char_u **arg, typval_T *rettv, int evaluate) /* * Get the first variable. */ - if (eval5(arg, rettv, evaluate) == FAIL) + if (eval5(arg, rettv, flags) == FAIL) return FAIL; p = *arg; @@ -2101,12 +2120,12 @@ eval4(char_u **arg, typval_T *rettv, int evaluate) * Get the second variable. */ *arg = skipwhite(p + len); - if (eval5(arg, &var2, evaluate) == FAIL) + if (eval5(arg, &var2, flags) == FAIL) { clear_tv(rettv); return FAIL; } - if (evaluate) + if (flags & EVAL_EVALUATE) { int ret = typval_compare(rettv, &var2, type, ic); @@ -2168,7 +2187,7 @@ eval_addlist(typval_T *tv1, typval_T *tv2) * Return OK or FAIL. */ static int -eval5(char_u **arg, typval_T *rettv, int evaluate) +eval5(char_u **arg, typval_T *rettv, int flags) { typval_T var2; int op; @@ -2184,7 +2203,7 @@ eval5(char_u **arg, typval_T *rettv, int evaluate) /* * Get the first variable. */ - if (eval6(arg, rettv, evaluate, FALSE) == FAIL) + if (eval6(arg, rettv, flags, FALSE) == FAIL) return FAIL; /* @@ -2213,7 +2232,7 @@ eval5(char_u **arg, typval_T *rettv, int evaluate) // 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) + if ((flags & EVAL_EVALUATE) && tv_get_string_chk(rettv) == NULL) { clear_tv(rettv); return FAIL; @@ -2226,13 +2245,13 @@ eval5(char_u **arg, typval_T *rettv, int evaluate) if (op == '.' && *(*arg + 1) == '.') // .. string concatenation ++*arg; *arg = skipwhite(*arg + 1); - if (eval6(arg, &var2, evaluate, op == '.') == FAIL) + if (eval6(arg, &var2, flags, op == '.') == FAIL) { clear_tv(rettv); return FAIL; } - if (evaluate) + if (flags & EVAL_EVALUATE) { /* * Compute the result. @@ -2354,7 +2373,7 @@ eval5(char_u **arg, typval_T *rettv, int evaluate) eval6( char_u **arg, typval_T *rettv, - int evaluate, + int flags, int want_string) // after "." operator { typval_T var2; @@ -2369,7 +2388,7 @@ eval6( /* * Get the first variable. */ - if (eval7(arg, rettv, evaluate, want_string) == FAIL) + if (eval7(arg, rettv, flags, want_string) == FAIL) return FAIL; /* @@ -2381,7 +2400,7 @@ eval6( if (op != '*' && op != '/' && op != '%') break; - if (evaluate) + if (flags & EVAL_EVALUATE) { #ifdef FEAT_FLOAT if (rettv->v_type == VAR_FLOAT) @@ -2404,10 +2423,10 @@ eval6( * Get the second variable. */ *arg = skipwhite(*arg + 1); - if (eval7(arg, &var2, evaluate, FALSE) == FAIL) + if (eval7(arg, &var2, flags, FALSE) == FAIL) return FAIL; - if (evaluate) + if (flags & EVAL_EVALUATE) { #ifdef FEAT_FLOAT if (var2.v_type == VAR_FLOAT) @@ -2524,9 +2543,10 @@ eval6( eval7( char_u **arg, typval_T *rettv, - int evaluate, + int flags, int want_string) // after "." operator { + int evaluate = flags & EVAL_EVALUATE; int len; char_u *s; char_u *start_leader, *end_leader; @@ -2591,7 +2611,7 @@ eval7( /* * List: [expr, expr] */ - case '[': ret = get_list_tv(arg, rettv, evaluate, TRUE); + case '[': ret = get_list_tv(arg, rettv, flags, TRUE); break; /* @@ -2600,7 +2620,7 @@ eval7( case '#': if ((*arg)[1] == '{') { ++*arg; - ret = eval_dict(arg, rettv, evaluate, TRUE); + ret = eval_dict(arg, rettv, flags, TRUE); } else ret = NOTDONE; @@ -2612,7 +2632,7 @@ eval7( */ case '{': ret = get_lambda_tv(arg, rettv, evaluate); if (ret == NOTDONE) - ret = eval_dict(arg, rettv, evaluate, FALSE); + ret = eval_dict(arg, rettv, flags, FALSE); break; /* @@ -2645,7 +2665,7 @@ eval7( * nested expression: (expression). */ case '(': *arg = skipwhite(*arg + 1); - ret = eval1(arg, rettv, evaluate); // recursive! + ret = eval1(arg, rettv, flags); // recursive! if (**arg == ')') ++*arg; else if (ret == OK) @@ -2676,7 +2696,9 @@ eval7( else { if (**arg == '(') // recursive! - ret = eval_func(arg, s, len, rettv, evaluate, NULL); + ret = eval_func(arg, s, len, rettv, flags, NULL); + else if (flags & EVAL_CONSTANT) + ret = FAIL; else if (evaluate) ret = get_var_tv(s, len, rettv, NULL, TRUE, FALSE); else @@ -2693,7 +2715,7 @@ eval7( // Handle following '[', '(' and '.' for expr[expr], expr.name, // expr(expr), expr->name(expr) if (ret == OK) - ret = handle_subscript(arg, rettv, evaluate, TRUE, + ret = handle_subscript(arg, rettv, flags, TRUE, start_leader, &end_leader); /* @@ -2915,7 +2937,8 @@ eval_method( ret = FAIL; } else - ret = eval_func(arg, name, len, rettv, evaluate, &base); + ret = eval_func(arg, name, len, rettv, + evaluate ? EVAL_EVALUATE : 0, &base); } // Clear the funcref afterwards, so that deleting it while @@ -2935,9 +2958,10 @@ eval_method( eval_index( char_u **arg, typval_T *rettv, - int evaluate, + int flags, int verbose) // give error messages { + int evaluate = flags & EVAL_EVALUATE; int empty1 = FALSE, empty2 = FALSE; typval_T var1, var2; long i; @@ -3006,7 +3030,7 @@ eval_index( *arg = skipwhite(*arg + 1); if (**arg == ':') empty1 = TRUE; - else if (eval1(arg, &var1, evaluate) == FAIL) // recursive! + else if (eval1(arg, &var1, flags) == FAIL) // recursive! return FAIL; else if (evaluate && tv_get_string_chk(&var1) == NULL) { @@ -3024,7 +3048,7 @@ eval_index( *arg = skipwhite(*arg + 1); if (**arg == ']') empty2 = TRUE; - else if (eval1(arg, &var2, evaluate) == FAIL) // recursive! + else if (eval1(arg, &var2, flags) == FAIL) // recursive! { if (!empty1) clear_tv(&var1); @@ -3480,6 +3504,7 @@ get_string_tv(char_u **arg, typval_T *rettv, int evaluate) char_u *p; char_u *name; int extra = 0; + int len; /* * Find the end of the string, skipping backslashed characters. @@ -3490,9 +3515,11 @@ get_string_tv(char_u **arg, typval_T *rettv, int evaluate) { ++p; // A "\" form occupies at least 4 characters, and produces up - // to 6 characters: reserve space for 2 extra + // to 21 characters (3 * 6 for the char and 3 for a modifier): + // reserve space for 18 extra. + // Each byte in the char could be encoded as K_SPECIAL K_EXTRA x. if (*p == '<') - extra += 2; + extra += 18; } } @@ -3513,7 +3540,8 @@ get_string_tv(char_u **arg, typval_T *rettv, int evaluate) * Copy the string into allocated memory, handling backslashed * characters. */ - name = alloc(p - *arg + extra); + len = (int)(p - *arg + extra); + name = alloc(len); if (name == NULL) return FAIL; rettv->v_type = VAR_STRING; @@ -3587,6 +3615,8 @@ get_string_tv(char_u **arg, typval_T *rettv, int evaluate) if (extra != 0) { name += extra; + if (name >= rettv->vval.v_string + len) + iemsg("get_string_tv() used more space than allocated"); break; } // FALLTHROUGH @@ -3678,7 +3708,9 @@ partial_name(partial_T *pt) { if (pt->pt_name != NULL) return pt->pt_name; - return pt->pt_func->uf_name; + if (pt->pt_func != NULL) + return pt->pt_func->uf_name; + return (char_u *)""; } static void @@ -3697,6 +3729,24 @@ partial_free(partial_T *pt) } else func_ptr_unref(pt->pt_func); + + if (pt->pt_funcstack != NULL) + { + // Decrease the reference count for the context of a closure. If down + // to zero free it and clear the variables on the stack. + if (--pt->pt_funcstack->fs_refcount == 0) + { + garray_T *gap = &pt->pt_funcstack->fs_ga; + typval_T *stack = gap->ga_data; + + for (i = 0; i < gap->ga_len; ++i) + clear_tv(stack + i); + ga_clear(gap); + vim_free(pt->pt_funcstack); + } + pt->pt_funcstack = NULL; + } + vim_free(pt); } @@ -4313,9 +4363,11 @@ set_ref_in_item( partial_T *pt = tv->vval.v_partial; int i; - // A partial does not have a copyID, because it cannot contain itself. - if (pt != NULL) + if (pt != NULL && pt->pt_copyID != copyID) { + // Didn't see this partial yet. + pt->pt_copyID = copyID; + abort = set_ref_in_func(pt->pt_name, pt->pt_func, copyID); if (pt->pt_dict != NULL) @@ -4330,6 +4382,15 @@ set_ref_in_item( for (i = 0; i < pt->pt_argc; ++i) abort = abort || set_ref_in_item(&pt->pt_argv[i], copyID, ht_stack, list_stack); + if (pt->pt_funcstack != NULL) + { + typval_T *stack = pt->pt_funcstack->fs_ga.ga_data; + + for (i = 0; i < pt->pt_funcstack->fs_ga.ga_len; ++i) + abort = abort || set_ref_in_item(stack + i, copyID, + ht_stack, list_stack); + } + } } #ifdef FEAT_JOB_CHANNEL @@ -4528,8 +4589,9 @@ echo_string_core( case VAR_LIST: if (tv->vval.v_list == NULL) { + // NULL list is equivalent to empty list. *tofree = NULL; - r = NULL; + r = (char_u *)"[]"; } else if (copyID != 0 && tv->vval.v_list->lv_copyID == copyID && tv->vval.v_list->lv_len > 0) @@ -4552,8 +4614,9 @@ echo_string_core( case VAR_DICT: if (tv->vval.v_dict == NULL) { + // NULL dict is equivalent to empty dict. *tofree = NULL; - r = NULL; + r = (char_u *)"{}"; } else if (copyID != 0 && tv->vval.v_dict->dv_copyID == copyID && tv->vval.v_dict->dv_hashtab.ht_used != 0) @@ -4564,6 +4627,7 @@ echo_string_core( 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) @@ -5272,11 +5336,12 @@ eval_isnamec1(int c) handle_subscript( char_u **arg, typval_T *rettv, - int evaluate, // do more than finding the end + int flags, // do more than finding the end int verbose, // give error messages char_u *start_leader, // start of '!' and '-' prefixes char_u **end_leaderp) // end of '!' and '-' prefixes { + int evaluate = flags & EVAL_EVALUATE; int ret = OK; dict_T *selfdict = NULL; @@ -5336,7 +5401,7 @@ handle_subscript( } else selfdict = NULL; - if (eval_index(arg, rettv, evaluate, verbose) == FAIL) + if (eval_index(arg, rettv, flags, verbose) == FAIL) { clear_tv(rettv); ret = FAIL; @@ -6070,7 +6135,7 @@ ex_echo(exarg_T *eap) need_clr_eos = needclr; p = arg; - if (eval1(&arg, &rettv, !eap->skip) == FAIL) + if (eval1(&arg, &rettv, eap->skip ? 0 : EVAL_EVALUATE) == FAIL) { /* * Report the invalid expression unless the expression evaluation @@ -6139,7 +6204,6 @@ ex_execute(exarg_T *eap) char_u *p; garray_T ga; int len; - int save_did_emsg; ga_init2(&ga, 1, 80); @@ -6207,8 +6271,9 @@ ex_execute(exarg_T *eap) } else if (eap->cmdidx == CMD_echoerr) { + int save_did_emsg = did_emsg; + // 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; @@ -6412,8 +6477,9 @@ typval_compare( && 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; + // When both partials are NULL, then they are equal. + // Otherwise they are not equal. + n1 = (typ1->vval.v_partial == typ2->vval.v_partial); else if (type_is) { if (typ1->v_type == VAR_FUNC && typ2->v_type == VAR_FUNC) diff --git a/src/evalbuffer.c b/src/evalbuffer.c index 2c20939bd4..adbbca3f7b 100644 --- a/src/evalbuffer.c +++ b/src/evalbuffer.c @@ -176,7 +176,14 @@ set_buffer_lines( if (lines->v_type == VAR_LIST) { l = lines->vval.v_list; - range_list_materialize(l); + if (l == NULL || list_len(l) == 0) + { + // set proper return code + if (lnum > curbuf->b_ml.ml_line_count) + rettv->vval.v_number = 1; // FAIL + goto done; + } + CHECK_LIST_MATERIALIZE(l); li = l->lv_first; } else @@ -251,6 +258,7 @@ set_buffer_lines( update_topline(); } +done: if (!is_curbuf) { curbuf = curbuf_save; diff --git a/src/evalfunc.c b/src/evalfunc.c index aa7d2370e4..a4f291ddf8 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -664,6 +664,7 @@ static funcentry_T global_functions[] = {"map", 2, 2, FEARG_1, ret_any, f_map}, {"maparg", 1, 4, FEARG_1, ret_string, f_maparg}, {"mapcheck", 1, 3, FEARG_1, ret_string, f_mapcheck}, + {"mapset", 3, 3, FEARG_1, ret_void, f_mapset}, {"match", 2, 4, FEARG_1, ret_any, f_match}, {"matchadd", 2, 5, FEARG_1, ret_number, f_matchadd}, {"matchaddpos", 2, 5, FEARG_1, ret_number, f_matchaddpos}, @@ -704,7 +705,7 @@ static funcentry_T global_functions[] = }, {"popup_atcursor", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_atcursor)}, {"popup_beval", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_beval)}, - {"popup_clear", 0, 0, 0, ret_void, PROP_FUNC(f_popup_clear)}, + {"popup_clear", 0, 1, 0, ret_void, PROP_FUNC(f_popup_clear)}, {"popup_close", 1, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_close)}, {"popup_create", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_create)}, {"popup_dialog", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_dialog)}, @@ -715,6 +716,7 @@ static funcentry_T global_functions[] = {"popup_getoptions", 1, 1, FEARG_1, ret_dict_any, PROP_FUNC(f_popup_getoptions)}, {"popup_getpos", 1, 1, FEARG_1, ret_dict_any, PROP_FUNC(f_popup_getpos)}, {"popup_hide", 1, 1, FEARG_1, ret_void, PROP_FUNC(f_popup_hide)}, + {"popup_list", 0, 0, 0, ret_list_number, PROP_FUNC(f_popup_list)}, {"popup_locate", 2, 2, 0, ret_number, PROP_FUNC(f_popup_locate)}, {"popup_menu", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_menu)}, {"popup_move", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_move)}, @@ -2131,7 +2133,7 @@ f_eval(typval_T *argvars, typval_T *rettv) s = skipwhite(s); p = s; - if (s == NULL || eval1(&s, rettv, TRUE) == FAIL) + if (s == NULL || eval1(&s, rettv, EVAL_EVALUATE) == FAIL) { if (p != NULL && !aborting()) semsg(_(e_invexpr2), p); @@ -2149,7 +2151,7 @@ f_eval(typval_T *argvars, typval_T *rettv) static void f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv) { - rettv->vval.v_number = vgetc_busy; + rettv->vval.v_number = vgetc_busy || input_busy; } static garray_T redir_execute_ga; @@ -2274,7 +2276,7 @@ execute_common(typval_T *argvars, typval_T *rettv, int arg_off) { listitem_T *item; - range_list_materialize(list); + CHECK_LIST_MATERIALIZE(list); item = list->lv_first; do_cmdline(NULL, get_list_line, (void *)&item, DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED); @@ -2566,7 +2568,7 @@ f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED) #ifdef FEAT_TIMERS || timer_busy #endif - ) + || input_busy) typebuf_was_filled = TRUE; } vim_free(keys_esc); @@ -2601,9 +2603,9 @@ f_float2nr(typval_T *argvars, typval_T *rettv) if (get_float_arg(argvars, &f) == OK) { - if (f <= -VARNUM_MAX + DBL_EPSILON) + if (f <= (float_T)-VARNUM_MAX + DBL_EPSILON) rettv->vval.v_number = -VARNUM_MAX; - else if (f >= VARNUM_MAX - DBL_EPSILON) + else if (f >= (float_T)VARNUM_MAX - DBL_EPSILON) rettv->vval.v_number = VARNUM_MAX; else rettv->vval.v_number = (varnumber_T)f; @@ -2679,6 +2681,7 @@ common_function(typval_T *argvars, typval_T *rettv, int is_funcref) int use_string = FALSE; partial_T *arg_pt = NULL; char_u *trans_name = NULL; + int is_global = FALSE; if (argvars[0].v_type == VAR_FUNC) { @@ -2702,21 +2705,10 @@ common_function(typval_T *argvars, typval_T *rettv, int is_funcref) if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref) { name = s; - trans_name = trans_function_name(&name, FALSE, + trans_name = trans_function_name(&name, &is_global, FALSE, TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL); if (*name != NUL) s = NULL; - else if (trans_name != NULL - && ASCII_ISUPPER(*s) - && current_sctx.sc_version == SCRIPT_VERSION_VIM9 - && find_func(trans_name, NULL) == NULL) - { - // With Vim9 script "MyFunc" can be script-local to the current - // script or global. The script-local name is not found, assume - // global. - vim_free(trans_name); - trans_name = vim_strsave(s); - } } if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s)) @@ -2724,8 +2716,8 @@ common_function(typval_T *argvars, typval_T *rettv, int is_funcref) 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) == NULL - : !translated_function_exists(trans_name))) + ? find_func(trans_name, is_global, NULL) == NULL + : !translated_function_exists(trans_name, is_global))) semsg(_("E700: Unknown function: %s"), s); else { @@ -2829,7 +2821,7 @@ common_function(typval_T *argvars, typval_T *rettv, int is_funcref) copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]); if (lv_len > 0) { - range_list_materialize(list); + CHECK_LIST_MATERIALIZE(list); FOR_ALL_LIST_ITEMS(list, li) copy_tv(&li->li_tv, &pt->pt_argv[i++]); } @@ -2862,7 +2854,7 @@ common_function(typval_T *argvars, typval_T *rettv, int is_funcref) } else if (is_funcref) { - pt->pt_func = find_func(trans_name, NULL); + pt->pt_func = find_func(trans_name, is_global, NULL); func_ptr_ref(pt->pt_func); vim_free(name); } @@ -2897,7 +2889,7 @@ f_funcref(typval_T *argvars, typval_T *rettv) } static type_T * -ret_f_function(int argcount, type_T **argtypes UNUSED) +ret_f_function(int argcount, type_T **argtypes) { if (argcount == 1 && argtypes[0]->tt_type == VAR_STRING) return &t_func_any; @@ -4956,7 +4948,7 @@ f_index(typval_T *argvars, typval_T *rettv) l = argvars[0].vval.v_list; if (l != NULL) { - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); item = l->lv_first; if (argvars[2].v_type != VAR_UNKNOWN) { @@ -5062,7 +5054,7 @@ f_inputlist(typval_T *argvars, typval_T *rettv) msg_clr_eos(); l = argvars[0].vval.v_list; - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); FOR_ALL_LIST_ITEMS(l, li) { msg_puts((char *)tv_get_string(&li->li_tv)); @@ -5538,7 +5530,7 @@ find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type) { if ((l = argvars[0].vval.v_list) == NULL) goto theend; - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); li = l->lv_first; } else @@ -6323,7 +6315,7 @@ f_range(typval_T *argvars, typval_T *rettv) list_T *list = rettv->vval.v_list; // Create a non-materialized list. This is much more efficient and - // works with ":for". If used otherwise range_list_materialize() must + // works with ":for". If used otherwise CHECK_LIST_MATERIALIZE() must // be called. list->lv_first = &range_list_item; list->lv_u.nonmat.lv_start = start; @@ -6334,26 +6326,24 @@ f_range(typval_T *argvars, typval_T *rettv) } /* - * If "list" is a non-materialized list then materialize it now. + * Materialize "list". + * Do not call directly, use CHECK_LIST_MATERIALIZE() */ void range_list_materialize(list_T *list) { - if (list->lv_first == &range_list_item) - { - varnumber_T start = list->lv_u.nonmat.lv_start; - varnumber_T end = list->lv_u.nonmat.lv_end; - int stride = list->lv_u.nonmat.lv_stride; - varnumber_T i; + varnumber_T start = list->lv_u.nonmat.lv_start; + varnumber_T end = list->lv_u.nonmat.lv_end; + int stride = list->lv_u.nonmat.lv_stride; + varnumber_T i; - list->lv_first = NULL; - list->lv_u.mat.lv_last = NULL; - list->lv_len = 0; - list->lv_u.mat.lv_idx_item = NULL; - for (i = start; stride > 0 ? i <= end : i >= end; i += stride) - if (list_append_number(list, (varnumber_T)i) == FAIL) - break; - } + list->lv_first = NULL; + list->lv_u.mat.lv_last = NULL; + list->lv_len = 0; + list->lv_u.mat.lv_idx_item = NULL; + for (i = start; stride > 0 ? i <= end : i >= end; i += stride) + if (list_append_number(list, (varnumber_T)i) == FAIL) + break; } static void @@ -7371,7 +7361,7 @@ f_setreg(typval_T *argvars, typval_T *rettv) if (ll != NULL) { - range_list_materialize(ll); + CHECK_LIST_MATERIALIZE(ll); FOR_ALL_LIST_ITEMS(ll, li) { strval = tv_get_string_buf_chk(&li->li_tv, buf); diff --git a/src/evalvars.c b/src/evalvars.c index 8e4a32daae..f932352ac9 100644 --- a/src/evalvars.c +++ b/src/evalvars.c @@ -166,7 +166,6 @@ static dict_T vimvardict; // Dictionary with v: variables // for VIM_VERSION_ defines #include "version.h" -static void ex_let_const(exarg_T *eap, int is_const); static char_u *skip_var_one(char_u *arg, int include_type); static void list_glob_vars(int *first); static void list_buf_vars(int *first); @@ -436,7 +435,7 @@ eval_spell_expr(char_u *badword, char_u *expr) if (p_verbose == 0) ++emsg_off; - if (eval1(&p, &rettv, TRUE) == OK) + if (eval1(&p, &rettv, EVAL_EVALUATE) == OK) { if (rettv.v_type != VAR_LIST) clear_tv(&rettv); @@ -597,7 +596,7 @@ heredoc_get(exarg_T *eap, char_u *cmd, int script_get) return NULL; } *p = NUL; - if (vim_islower(*marker)) + if (!script_get && vim_islower(*marker)) { emsg(_("E221: Marker cannot start with lower case letter")); return NULL; @@ -684,27 +683,14 @@ heredoc_get(exarg_T *eap, char_u *cmd, int script_get) * ":let [var1, var2] = expr" unpack list. * ":let var =<< ..." heredoc * ":let var: string" Vim9 declaration - */ - void -ex_let(exarg_T *eap) -{ - ex_let_const(eap, FALSE); -} - -/* + * * ":const" list all variable values * ":const var1 var2" list variable values * ":const var = expr" assignment command. * ":const [var1, var2] = expr" unpack list. */ void -ex_const(exarg_T *eap) -{ - ex_let_const(eap, TRUE); -} - - static void -ex_let_const(exarg_T *eap, int is_const) +ex_let(exarg_T *eap) { char_u *arg = eap->arg; char_u *expr = NULL; @@ -716,7 +702,8 @@ ex_let_const(exarg_T *eap, int is_const) char_u *argend; int first = TRUE; int concat; - int flags = is_const ? LET_IS_CONST : 0; + int has_assign; + int flags = eap->cmdidx == CMD_const ? LET_IS_CONST : 0; // detect Vim9 assignment without ":let" or ":const" if (eap->arg == eap->cmd) @@ -731,15 +718,16 @@ ex_let_const(exarg_T *eap, int is_const) concat = expr[0] == '.' && ((expr[1] == '=' && current_sctx.sc_version < 2) || (expr[1] == '.' && expr[2] == '=')); - if (*expr != '=' && !((vim_strchr((char_u *)"+-*/%", *expr) != NULL - && expr[1] == '=') || concat)) + has_assign = *expr == '=' || (vim_strchr((char_u *)"+-*/%", *expr) != NULL + && expr[1] == '='); + if (!has_assign && !concat) { // ":let" without "=": list variables if (*arg == '[') emsg(_(e_invarg)); else if (expr[0] == '.') emsg(_("E985: .= is not supported with script version 2")); - else if (!ends_excmd(*arg)) + else if (!ends_excmd2(eap->cmd, arg)) // ":let var1 var2" arg = list_arg_vars(eap, arg, &first); else if (!eap->skip) @@ -776,24 +764,32 @@ ex_let_const(exarg_T *eap, int is_const) } else { - op[0] = '='; - op[1] = NUL; - if (*expr != '=') - { - if (vim_strchr((char_u *)"+-*/%.", *expr) != NULL) - { - op[0] = *expr; // +=, -=, *=, /=, %= or .= - if (expr[0] == '.' && expr[1] == '.') // ..= - ++expr; - } - expr = skipwhite(expr + 2); - } - else - expr = skipwhite(expr + 1); + int eval_flags; - if (eap->skip) - ++emsg_skip; - i = eval0(expr, &rettv, &eap->nextcmd, !eap->skip); + rettv.v_type = VAR_UNKNOWN; + i = FAIL; + if (has_assign || concat) + { + op[0] = '='; + op[1] = NUL; + if (*expr != '=') + { + if (vim_strchr((char_u *)"+-*/%.", *expr) != NULL) + { + op[0] = *expr; // +=, -=, *=, /=, %= or .= + if (expr[0] == '.' && expr[1] == '.') // ..= + ++expr; + } + expr = skipwhite(expr + 2); + } + else + expr = skipwhite(expr + 1); + + if (eap->skip) + ++emsg_skip; + eval_flags = eap->skip ? 0 : EVAL_EVALUATE; + i = eval0(expr, &rettv, &eap->nextcmd, eval_flags); + } if (eap->skip) { if (i != FAIL) @@ -860,7 +856,7 @@ ex_let_vars( return FAIL; } - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); item = l->lv_first; while (*arg != ']') { @@ -1070,7 +1066,7 @@ list_arg_vars(exarg_T *eap, char_u *arg, int *first) char_u *tofree; typval_T tv; - while (!ends_excmd(*arg) && !got_int) + while (!ends_excmd2(eap->cmd, arg) && !got_int) { if (error || eap->skip) { @@ -1109,7 +1105,7 @@ list_arg_vars(exarg_T *eap, char_u *arg, int *first) { // handle d.key, l[idx], f(expr) arg_subsc = arg; - if (handle_subscript(&arg, &tv, TRUE, TRUE, + if (handle_subscript(&arg, &tv, EVAL_EVALUATE, TRUE, name, &name) == FAIL) error = TRUE; else @@ -1253,13 +1249,15 @@ ex_let_one( int opt_type; long numval; char_u *stringval = NULL; - char_u *s; + char_u *s = NULL; c1 = *p; *p = NUL; n = (long)tv_get_number(tv); - s = tv_get_string_chk(tv); // != NULL if number or string + // avoid setting a string option to the text "v:false" or similar. + if (tv->v_type != VAR_BOOL && tv->v_type != VAR_SPECIAL) + s = tv_get_string_chk(tv); // != NULL if number or string if (s != NULL && op != NULL && *op != '=') { opt_type = get_option_value(arg, &numval, @@ -1291,7 +1289,8 @@ ex_let_one( } } } - if (s != NULL) + if (s != NULL || tv->v_type == VAR_BOOL + || tv->v_type == VAR_SPECIAL) { set_option_value(arg, n, s, opt_flags); arg_end = p; @@ -2494,21 +2493,22 @@ get_script_local_ht(void) /* * Look for "name[len]" in script-local variables. - * Return -1 when not found. + * Return a non-NULL pointer when found, NULL when not found. */ - int + void * lookup_scriptvar(char_u *name, size_t len, cctx_T *dummy UNUSED) { hashtab_T *ht = get_script_local_ht(); char_u buffer[30]; char_u *p; - int res; + void *res; hashitem_T *hi; if (ht == NULL) - return -1; + return NULL; if (len < sizeof(buffer) - 1) { + // avoid an alloc/free for short names vim_strncpy(buffer, name, len); p = buffer; } @@ -2516,19 +2516,20 @@ lookup_scriptvar(char_u *name, size_t len, cctx_T *dummy UNUSED) { p = vim_strnsave(name, (int)len); if (p == NULL) - return -1; + return NULL; } hi = hash_find(ht, p); - res = HASHITEM_EMPTY(hi) ? -1 : 1; + res = HASHITEM_EMPTY(hi) ? NULL : hi; // if not script-local, then perhaps imported - if (res == -1 && find_imported(p, 0, NULL) != NULL) - res = 1; + if (res == NULL && find_imported(p, 0, NULL) != NULL) + res = p; if (p != buffer) vim_free(p); - return res; + // Don't return "buffer", gcc complains. + return res == NULL ? NULL : IObuff; } /* @@ -2590,7 +2591,7 @@ find_var_ht(char_u *name, char_u **varname) if (*name == 'v') // v: variable return &vimvarht; if (get_current_funccal() != NULL - && get_current_funccal()->func->uf_dfunc_idx < 0) + && get_current_funccal()->func->uf_dfunc_idx == UF_NOT_COMPILED) { // a: and l: are only used in functions defined with ":function" if (*name == 'a') // a: function argument @@ -3278,7 +3279,8 @@ var_exists(char_u *var) if (n) { // handle d.key, l[idx], f(expr) - n = (handle_subscript(&var, &tv, TRUE, FALSE, name, &name) == OK); + n = (handle_subscript(&var, &tv, EVAL_EVALUATE, + FALSE, name, &name) == OK); if (n) clear_tv(&tv); } diff --git a/src/ex_cmdidxs.h b/src/ex_cmdidxs.h index 72fd58e4c7..dadbc552b5 100644 --- a/src/ex_cmdidxs.h +++ b/src/ex_cmdidxs.h @@ -9,28 +9,28 @@ static const unsigned short cmdidxs1[26] = /* b */ 19, /* c */ 42, /* d */ 108, - /* e */ 132, - /* f */ 155, - /* g */ 171, - /* h */ 177, - /* i */ 186, - /* j */ 205, - /* k */ 207, - /* l */ 212, - /* m */ 274, - /* n */ 294, - /* o */ 314, - /* p */ 326, - /* q */ 365, - /* r */ 368, - /* s */ 388, - /* t */ 457, - /* u */ 502, - /* v */ 513, - /* w */ 532, - /* x */ 546, - /* y */ 556, - /* z */ 557 + /* e */ 133, + /* f */ 156, + /* g */ 172, + /* h */ 178, + /* i */ 187, + /* j */ 206, + /* k */ 208, + /* l */ 213, + /* m */ 275, + /* n */ 295, + /* o */ 315, + /* p */ 327, + /* q */ 366, + /* r */ 369, + /* s */ 389, + /* t */ 458, + /* u */ 503, + /* v */ 514, + /* w */ 533, + /* x */ 547, + /* y */ 557, + /* z */ 558 }; /* @@ -44,7 +44,7 @@ static const unsigned char cmdidxs2[26][26] = /* 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, 12, 16, 18, 20, 22, 25, 0, 0, 0, 0, 33, 37, 40, 46, 56, 58, 59, 60, 0, 62, 0, 65, 0, 0, 0 }, - /* d */ { 0, 0, 0, 0, 0, 0, 0, 0, 7, 17, 0, 18, 0, 0, 19, 0, 0, 21, 22, 0, 0, 0, 0, 0, 0, 0 }, + /* d */ { 0, 0, 0, 0, 0, 0, 0, 0, 8, 18, 0, 19, 0, 0, 20, 0, 0, 22, 23, 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, 17, 0, 18, 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 }, @@ -69,4 +69,4 @@ static const unsigned char cmdidxs2[26][26] = /* 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 = 570; +static const int command_count = 571; diff --git a/src/ex_cmds.c b/src/ex_cmds.c index bd114631bb..9c55de3adf 100644 --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -451,12 +451,9 @@ ex_sort(exarg_T *eap) } else if (!ASCII_ISALPHA(*p) && regmatch.regprog == NULL) { - s = skip_regexp(p + 1, *p, TRUE); - if (*s != *p) - { - emsg(_(e_invalpat)); + s = skip_regexp_err(p + 1, *p, TRUE); + if (s == NULL) goto sortend; - } *s = NUL; // Use last search pattern if sort pattern is empty. if (s == p + 1) @@ -2487,6 +2484,11 @@ do_ecmd( int did_inc_redrawing_disabled = FALSE; long *so_ptr = curwin->w_p_so >= 0 ? &curwin->w_p_so : &p_so; +#ifdef FEAT_PROP_POPUP + if (ERROR_IF_TERM_POPUP_WINDOW) + return FAIL; +#endif + if (eap != NULL) command = eap->do_ecmd_cmd; set_bufref(&old_curbuf, curbuf); diff --git a/src/ex_cmds.h b/src/ex_cmds.h index a38b77ddf3..5ff207ee3b 100644 --- a/src/ex_cmds.h +++ b/src/ex_cmds.h @@ -53,6 +53,8 @@ #define EX_MODIFY 0x100000 // forbidden in non-'modifiable' buffer #define EX_FLAGS 0x200000 // allow flags after count in argument #define EX_RESTRICT 0x400000 // forbidden in restricted mode +#define EX_EXPAND 0x800000 // expands wildcards later + #define EX_FILES (EX_XFILE | EX_EXTRA) // multiple extra files allowed #define EX_FILE1 (EX_FILES | EX_NOSPC) // 1 file, defaults to current file #define EX_WORD1 (EX_EXTRA | EX_NOSPC) // one extra word allowed @@ -394,7 +396,7 @@ EXCMD(CMD_continue, "continue", ex_continue, EXCMD(CMD_confirm, "confirm", ex_wrongmodifier, EX_NEEDARG|EX_EXTRA|EX_NOTRLCOM|EX_CMDWIN, ADDR_NONE), -EXCMD(CMD_const, "const", ex_const, +EXCMD(CMD_const, "const", ex_let, EX_EXTRA|EX_NOTRLCOM|EX_SBOXOK|EX_CMDWIN, ADDR_NONE), EXCMD(CMD_copen, "copen", ex_copen, @@ -445,6 +447,9 @@ EXCMD(CMD_debuggreedy, "debuggreedy", ex_debuggreedy, EXCMD(CMD_def, "def", ex_function, EX_EXTRA|EX_BANG|EX_SBOXOK|EX_CMDWIN, ADDR_NONE), +EXCMD(CMD_defcompile, "defcompile", ex_defcompile, + EX_SBOXOK|EX_CMDWIN|EX_TRLBAR, + ADDR_NONE), EXCMD(CMD_delcommand, "delcommand", ex_delcommand, EX_NEEDARG|EX_WORD1|EX_TRLBAR|EX_CMDWIN, ADDR_NONE), @@ -653,7 +658,7 @@ EXCMD(CMD_helptags, "helptags", ex_helptags, EX_NEEDARG|EX_FILES|EX_TRLBAR|EX_CMDWIN, ADDR_NONE), EXCMD(CMD_hardcopy, "hardcopy", ex_hardcopy, - EX_RANGE|EX_COUNT|EX_EXTRA|EX_TRLBAR|EX_DFLALL|EX_BANG, + EX_RANGE|EX_COUNT|EX_EXTRA|EX_EXPAND|EX_TRLBAR|EX_DFLALL|EX_BANG, ADDR_LINES), EXCMD(CMD_highlight, "highlight", ex_highlight, EX_BANG|EX_EXTRA|EX_TRLBAR|EX_SBOXOK|EX_CMDWIN, diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 91fcf11576..b0927c3a95 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -270,10 +270,11 @@ static void ex_tag_cmd(exarg_T *eap, char_u *name); # define ex_call ex_ni # define ex_catch ex_ni # define ex_compiler ex_ni -# define ex_const ex_ni # define ex_continue ex_ni # define ex_debug ex_ni # define ex_debuggreedy ex_ni +# define ex_def ex_ni +# define ex_defcompile ex_ni # define ex_delfunction ex_ni # define ex_disassemble ex_ni # define ex_echo ex_ni @@ -639,8 +640,8 @@ do_cmdline( 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; + msglist_T **saved_msg_list = NULL; + msglist_T *private_msg_list; // "fgetline" and "cookie" passed to do_one_cmd() char_u *(*cmd_getline)(int, void *, int, int); @@ -1243,7 +1244,7 @@ do_cmdline( if (did_throw) { void *p = NULL; - struct msglist *messages = NULL, *next; + msglist_T *messages = NULL, *next; /* * If the uncaught exception is a user exception, report it as an @@ -2924,8 +2925,12 @@ parse_cmd_address(exarg_T *eap, char **errormsg, int silent) { case ADDR_LINES: case ADDR_OTHER: - // default is current line number - eap->line2 = curwin->w_cursor.lnum; + // Default is the cursor line number. Avoid using an invalid + // line number though. + if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) + eap->line2 = curbuf->b_ml.ml_line_count; + else + eap->line2 = curwin->w_cursor.lnum; break; case ADDR_WINDOWS: eap->line2 = CURRENT_WIN_NR; @@ -3075,8 +3080,10 @@ parse_cmd_address(exarg_T *eap, char **errormsg, int silent) if (!eap->skip) { curwin->w_cursor.lnum = eap->line2; - // don't leave the cursor on an illegal line or column - check_cursor(); + // Don't leave the cursor on an illegal line or column, but do + // accept zero as address, so 0;/PATTERN/ works correctly. + if (eap->line2 > 0) + check_cursor(); } } else if (*eap->cmd != ',') @@ -3161,7 +3168,7 @@ append_command(char_u *cmd) find_ex_command( exarg_T *eap, int *full UNUSED, - int (*lookup)(char_u *, size_t, cctx_T *) UNUSED, + void *(*lookup)(char_u *, size_t, cctx_T *) UNUSED, cctx_T *cctx UNUSED) { int len; @@ -3201,7 +3208,7 @@ find_ex_command( // "g:var = expr" // "var = expr" where "var" is a local var name. if (((p - eap->cmd) > 2 && eap->cmd[1] == ':') - || lookup(eap->cmd, p - eap->cmd, cctx) >= 0) + || lookup(eap->cmd, p - eap->cmd, cctx) != NULL) { eap->cmdidx = CMD_let; return eap->cmd; @@ -5753,7 +5760,7 @@ handle_drop( handle_any_postponed_drop(void) { if (!drop_busy && drop_filev != NULL - && !text_locked() && !curbuf_locked() && !updating_screen) + && !text_locked() && !curbuf_locked() && !updating_screen) handle_drop_internal(); } #endif @@ -7919,7 +7926,7 @@ ex_findpat(exarg_T *eap) p = skipwhite(p); // Check for trailing illegal characters - if (!ends_excmd(*p)) + if (!ends_excmd2(eap->arg, p)) eap->errmsg = e_trailing; else eap->nextcmd = check_nextcmd(p); diff --git a/src/ex_eval.c b/src/ex_eval.c index 7ffc145ae4..68207cbe7c 100644 --- a/src/ex_eval.c +++ b/src/ex_eval.c @@ -146,8 +146,8 @@ cause_errthrow( int severe, int *ignore) { - struct msglist *elem; - struct msglist **plist; + msglist_T *elem; + msglist_T **plist; /* * Do nothing when displaying the interrupt message or reporting an @@ -251,7 +251,7 @@ cause_errthrow( while (*plist != NULL) plist = &(*plist)->next; - elem = ALLOC_ONE(struct msglist); + elem = ALLOC_CLEAR_ONE(msglist_T); if (elem == NULL) { suppress_errthrow = TRUE; @@ -287,6 +287,11 @@ cause_errthrow( else (*msg_list)->throw_msg = tmsg; } + + // Get the source name and lnum now, it may change before + // reaching do_errthrow(). + elem->sfile = estack_sfile(); + elem->slnum = SOURCING_LNUM; } } } @@ -298,15 +303,16 @@ cause_errthrow( * Free a "msg_list" and the messages it contains. */ static void -free_msglist(struct msglist *l) +free_msglist(msglist_T *l) { - struct msglist *messages, *next; + msglist_T *messages, *next; messages = l; while (messages != NULL) { next = messages->next; vim_free(messages->msg); + vim_free(messages->sfile); vim_free(messages); messages = next; } @@ -428,7 +434,7 @@ get_exception_string( if (type == ET_ERROR) { *should_free = TRUE; - mesg = ((struct msglist *)value)->throw_msg; + mesg = ((msglist_T *)value)->throw_msg; if (cmdname != NULL && *cmdname != NUL) { cmdlen = (int)STRLEN(cmdname); @@ -526,23 +532,34 @@ throw_exception(void *value, except_type_T type, char_u *cmdname) 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->messages = (msglist_T *)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 = estack_sfile(); - if (excp->throw_name == NULL) - excp->throw_name = vim_strsave((char_u *)""); - if (excp->throw_name == NULL) + if (type == ET_ERROR && ((msglist_T *)value)->sfile != NULL) { - if (should_free) - vim_free(excp->value); - goto nomem; + msglist_T *entry = (msglist_T *)value; + + excp->throw_name = entry->sfile; + entry->sfile = NULL; + excp->throw_lnum = entry->slnum; + } + else + { + excp->throw_name = estack_sfile(); + if (excp->throw_name == NULL) + excp->throw_name = vim_strsave((char_u *)""); + if (excp->throw_name == NULL) + { + if (should_free) + vim_free(excp->value); + goto nomem; + } + excp->throw_lnum = SOURCING_LNUM; } - excp->throw_lnum = SOURCING_LNUM; if (p_verbose >= 13 || debug_break_level > 0) { @@ -879,7 +896,8 @@ ex_eval(exarg_T *eap) { typval_T tv; - if (eval0(eap->arg, &tv, &eap->nextcmd, !eap->skip) == OK) + if (eval0(eap->arg, &tv, &eap->nextcmd, eap->skip ? 0 : EVAL_EVALUATE) + == OK) clear_tv(&tv); } @@ -1021,12 +1039,12 @@ ex_else(exarg_T *eap) 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) @@ -1518,7 +1536,7 @@ ex_catch(exarg_T *eap) &cstack->cs_looplevel); } - if (ends_excmd(*eap->arg)) // no argument, catch all errors + if (ends_excmd2(eap->cmd, eap->arg)) // no argument, catch all errors { pat = (char_u *)".*"; end = NULL; @@ -1527,7 +1545,9 @@ ex_catch(exarg_T *eap) else { pat = eap->arg + 1; - end = skip_regexp(pat, *eap->arg, TRUE); + end = skip_regexp_err(pat, *eap->arg, TRUE); + if (end == NULL) + give_up = TRUE; } if (!give_up) @@ -1548,7 +1568,8 @@ ex_catch(exarg_T *eap) if (!skip && (cstack->cs_flags[idx] & CSF_THROWN) && !(cstack->cs_flags[idx] & CSF_CAUGHT)) { - if (end != NULL && *end != NUL && !ends_excmd(*skipwhite(end + 1))) + if (end != NULL && *end != NUL + && !ends_excmd2(end, skipwhite(end + 1))) { emsg(_(e_trailing)); return; diff --git a/src/ex_getln.c b/src/ex_getln.c index ae35064d6f..9a784d0f17 100644 --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -249,7 +249,9 @@ do_incsearch_highlighting(int firstc, int *search_delim, incsearch_state_T *is_s } else if (STRNCMP(cmd, "sort", MAX(p - cmd, 3)) == 0) { - // skip over flags + // skip over ! and flags + if (*p == '!') + p = skipwhite(p + 1); while (ASCII_ISALPHA(*(p = skipwhite(p)))) ++p; if (*p == NUL) @@ -1316,12 +1318,12 @@ getcmdline_int( c = get_expr_register(); if (c == '=') { - // Need to save and restore ccline. And set "textlock" + // Need to save and restore ccline. And set "textwinlock" // to avoid nasty things like going to another buffer when // evaluating an expression. - ++textlock; + ++textwinlock; p = get_expr_line(); - --textlock; + --textwinlock; if (p != NULL) { @@ -2555,17 +2557,17 @@ check_opt_wim(void) /* * 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 + * another window or buffer. TRUE when editing the command line, evaluating * 'balloonexpr', etc. */ int -text_locked(void) +text_and_win_locked(void) { #ifdef FEAT_CMDWIN if (cmdwin_type != 0) return TRUE; #endif - return textlock != 0; + return textwinlock != 0; } /* @@ -2585,7 +2587,19 @@ get_text_locked_msg(void) if (cmdwin_type != 0) return e_cmdwin; #endif - return e_secure; + if (textwinlock != 0) + return e_textwinlock; + return e_textlock; +} + +/* + * Return TRUE when the text must not be changed and/or we cannot switch to + * another window. TRUE while evaluating 'completefunc'. + */ + int +text_locked(void) +{ + return text_and_win_locked() || textlock != 0; } /* @@ -3570,11 +3584,11 @@ cmdline_paste( regname = may_get_selection(regname); #endif - // Need to set "textlock" to avoid nasty things like going to another + // Need to set "textwinlock" to avoid nasty things like going to another // buffer when evaluating an expression. - ++textlock; + ++textwinlock; i = get_spec_reg(regname, &arg, &allocated, TRUE); - --textlock; + --textwinlock; if (i) { @@ -4478,6 +4492,8 @@ get_user_input( rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; + if (input_busy) + return; // this doesn't work recursively. #ifdef NO_CONSOLE_INPUT // While starting up, there is no place to enter text. When running tests @@ -4538,12 +4554,18 @@ get_user_input( if (defstr != NULL) { int save_ex_normal_busy = ex_normal_busy; + int save_vgetc_busy = vgetc_busy; + int save_input_busy = input_busy; + input_busy |= vgetc_busy; ex_normal_busy = 0; + vgetc_busy = 0; rettv->vval.v_string = getcmdline_prompt(secret ? NUL : '@', p, get_echo_attr(), xp_type, xp_arg); ex_normal_busy = save_ex_normal_busy; + vgetc_busy = save_vgetc_busy; + input_busy = save_input_busy; } if (inputdialog && rettv->vval.v_string == NULL && argvars[1].v_type != VAR_UNKNOWN diff --git a/src/fileio.c b/src/fileio.c index 030c1b4357..d29ae64e1d 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -4655,6 +4655,42 @@ delete_recursive(char_u *name) #if defined(TEMPDIRNAMES) || defined(PROTO) static long temp_count = 0; // Temp filename counter. +# if defined(UNIX) && defined(HAVE_FLOCK) && defined(HAVE_DIRFD) +/* + * Open temporary directory and take file lock to prevent + * to be auto-cleaned. + */ + static void +vim_opentempdir(void) +{ + DIR *dp = NULL; + + if (vim_tempdir_dp != NULL) + return; + + dp = opendir((const char*)vim_tempdir); + + if (dp != NULL) + { + vim_tempdir_dp = dp; + flock(dirfd(vim_tempdir_dp), LOCK_SH); + } +} + +/* + * Close temporary directory - it automatically release file lock. + */ + static void +vim_closetempdir(void) +{ + if (vim_tempdir_dp != NULL) + { + closedir(vim_tempdir_dp); + vim_tempdir_dp = NULL; + } +} +# endif + /* * Delete the temp directory and all files it contains. */ @@ -4663,6 +4699,9 @@ vim_deltempdir(void) { if (vim_tempdir != NULL) { +# if defined(UNIX) && defined(HAVE_FLOCK) && defined(HAVE_DIRFD) + vim_closetempdir(); +# endif // remove the trailing path separator gettail(vim_tempdir)[-1] = NUL; delete_recursive(vim_tempdir); @@ -4687,6 +4726,9 @@ vim_settempdir(char_u *tempdir) STRCPY(buf, tempdir); add_pathsep(buf); vim_tempdir = vim_strsave(buf); +# if defined(UNIX) && defined(HAVE_FLOCK) && defined(HAVE_DIRFD) + vim_opentempdir(); +# endif vim_free(buf); } } diff --git a/src/filepath.c b/src/filepath.c index cbfb389893..b094dac100 100644 --- a/src/filepath.c +++ b/src/filepath.c @@ -1917,7 +1917,7 @@ f_writefile(typval_T *argvars, typval_T *rettv) list = argvars[0].vval.v_list; if (list == NULL) return; - range_list_materialize(list); + CHECK_LIST_MATERIALIZE(list); FOR_ALL_LIST_ITEMS(list, li) if (tv_get_string_chk(&li->li_tv) == NULL) return; diff --git a/src/getchar.c b/src/getchar.c index 2787a06c99..ef50ca4107 100644 --- a/src/getchar.c +++ b/src/getchar.c @@ -684,6 +684,46 @@ stuffnumReadbuff(long n) add_num_buff(&readbuf1, n); } +/* + * Stuff a string into the typeahead buffer, such that edit() will insert it + * literally ("literally" TRUE) or interpret is as typed characters. + */ + 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); + } + } +} + /* * Read a character from the redo buffer. Translates K_SPECIAL, CSI and * multibyte characters. @@ -2115,7 +2155,7 @@ parse_queued_messages(void) for (i = 0; i < MAX_REPEAT_PARSE; ++i) { // For Win32 mch_breakcheck() does not check for input, do it here. -# if defined(MSWIN) && defined(FEAT_JOB_CHANNEL) +# if (defined(MSWIN) || defined(__HAIKU__)) && defined(FEAT_JOB_CHANNEL) channel_handle_events(FALSE); # endif diff --git a/src/globals.h b/src/globals.h index 89a6d136b4..da69e04e7a 100644 --- a/src/globals.h +++ b/src/globals.h @@ -344,7 +344,7 @@ EXTERN int force_abort INIT(= FALSE); * 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); +EXTERN msglist_T **msg_list INIT(= NULL); /* * suppress_errthrow: When TRUE, don't convert an error to an exception. Used @@ -758,6 +758,9 @@ EXTERN int ru_wid; // 'rulerfmt' width of ruler when non-zero EXTERN int sc_col; // column for shown command #ifdef TEMPDIRNAMES +# if defined(UNIX) && defined(HAVE_FLOCK) && defined(HAVE_DIRFD) +EXTERN DIR *vim_tempdir_dp INIT(= NULL); // File descriptor of temp dir +# endif EXTERN char_u *vim_tempdir INIT(= NULL); // Name of Vim's own temp dir. // Ends in a slash. #endif @@ -798,9 +801,15 @@ EXTERN int secure INIT(= FALSE); // allowed, e.g. when sourcing .exrc or .vimrc // in current directory -EXTERN int textlock INIT(= 0); +EXTERN int textwinlock INIT(= 0); // non-zero when changing text and jumping to - // another window or buffer is not allowed + // another window or editing another buffer is + // not allowed + +EXTERN int textlock INIT(= 0); + // non-zero when changing text is not allowed, + // jumping to another window is allowed, + // editing another buffer is not allowed. EXTERN int curbuf_lock INIT(= 0); // non-zero when the current buffer can't be @@ -1164,7 +1173,7 @@ EXTERN volatile sig_atomic_t got_int INIT(= FALSE); // set to TRUE when interrup 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 tmode_T 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 @@ -1669,6 +1678,7 @@ EXTERN char e_toofewarg[] INIT(= N_("E119: Not enough arguments for function: %s EXTERN char e_func_deleted[] INIT(= N_("E933: Function was deleted: %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_listdictblobreq[] INIT(= N_("E1090: List, Dict or Blob required")); EXTERN char e_listblobreq[] INIT(= N_("E897: List or Blob required")); EXTERN char e_list_end[] INIT(= N_("E697: Missing end of List ']': %s")); EXTERN char e_listdictarg[] INIT(= N_("E712: Argument of %s must be a List or Dictionary")); @@ -1683,9 +1693,11 @@ EXTERN char e_letunexp[] INIT(= N_("E18: Unexpected characters in :let")); 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")); +EXTERN char e_sandbox[] INIT(= N_("E48: Not allowed in sandbox")); #endif -EXTERN char e_secure[] INIT(= N_("E523: Not allowed here")); +EXTERN char e_secure[] INIT(= N_("E523: Not allowed here")); +EXTERN char e_textlock[] INIT(= N_("E578: Not allowed to change text here")); +EXTERN char e_textwinlock[] INIT(= N_("E565: Not allowed to change text or change window")); #if defined(AMIGA) || defined(MACOS_X) || defined(MSWIN) \ || defined(UNIX) || defined(VMS) EXTERN char e_screenmode[] INIT(= N_("E359: Screen mode setting not supported")); @@ -1754,8 +1766,15 @@ EXTERN char e_endif_without_if[] INIT(= N_("E580: :endif without :if")); EXTERN char e_continue[] INIT(= N_("E586: :continue without :while or :for")); EXTERN char e_break[] INIT(= N_("E587: :break without :while or :for")); EXTERN char e_nowhitespace[] INIT(= N_("E274: No white space allowed before parenthesis")); +EXTERN char e_white_both[] INIT(= N_("E1004: white space required before and after '%s'")); +EXTERN char e_white_after[] INIT(= N_("E1069: white space required after '%s'")); +EXTERN char e_no_white_before[] INIT(= N_("E1068: No white space allowed before '%s'")); + EXTERN char e_lock_unlock[] INIT(= N_("E940: Cannot lock or unlock variable %s")); #endif +#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) +EXTERN char e_alloc_color[] INIT(= N_("E254: Cannot allocate color %s")); +#endif #ifdef FEAT_GUI_MAC EXTERN short disallow_gui INIT(= FALSE); @@ -1814,6 +1833,9 @@ EXTERN int in_free_unref_items INIT(= FALSE); EXTERN int did_add_timer INIT(= FALSE); EXTERN int timer_busy INIT(= 0); // when timer is inside vgetc() then > 0 #endif +#ifdef FEAT_EVAL +EXTERN int input_busy INIT(= 0); // when inside get_user_input() then > 0 +#endif #ifdef FEAT_BEVAL_TERM EXTERN int bevalexpr_due_set INIT(= FALSE); @@ -1823,6 +1845,8 @@ EXTERN proftime_T bevalexpr_due; #ifdef FEAT_EVAL EXTERN time_T time_for_testing INIT(= 0); +EXTERN int echo_attr INIT(= 0); // attributes used for ":echo" + // Abort conversion to string after a recursion error. EXTERN int did_echo_string_emsg INIT(= FALSE); diff --git a/src/gui.c b/src/gui.c index fa2b16e7e3..2caee826da 100644 --- a/src/gui.c +++ b/src/gui.c @@ -4781,7 +4781,7 @@ gui_get_color(char_u *name) && gui.in_use #endif ) - semsg(_("E254: Cannot allocate color %s"), name); + semsg(_(e_alloc_color), name); return t; } @@ -5087,7 +5087,7 @@ ex_gui(exarg_T *eap) // of the argument ending up after the shell prompt. msg_clr_eos_force(); #ifdef GUI_MAY_SPAWN - if (!ends_excmd(*eap->arg)) + if (!ends_excmd2(eap->cmd, eap->arg)) gui_start(eap->arg); else #endif @@ -5096,7 +5096,7 @@ ex_gui(exarg_T *eap) channel_gui_register_all(); #endif } - if (!ends_excmd(*eap->arg)) + if (!ends_excmd2(eap->cmd, eap->arg)) ex_next(eap); } @@ -5159,7 +5159,8 @@ gui_find_iconfile(char_u *name, char_u *buffer, char *ext) # endif #endif -#if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_X11) || defined(PROTO) +#if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_X11)|| defined(FEAT_GUI_HAIKU) \ + || defined(PROTO) void display_errors(void) { diff --git a/src/gui_gtk_x11.c b/src/gui_gtk_x11.c index ea43c93850..8e272970d2 100644 --- a/src/gui_gtk_x11.c +++ b/src/gui_gtk_x11.c @@ -1023,7 +1023,7 @@ focus_out_event(GtkWidget *widget UNUSED, * 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) +keyval_to_string(unsigned int keyval, unsigned int *state, char_u *string) { int len; guint32 uc; @@ -1031,8 +1031,8 @@ keyval_to_string(unsigned int keyval, unsigned int state, char_u *string) uc = gdk_keyval_to_unicode(keyval); if (uc != 0) { - // Check for CTRL-foo - if ((state & GDK_CONTROL_MASK) && uc >= 0x20 && uc < 0x80) + // Check for CTRL-char + 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 @@ -1051,6 +1051,10 @@ keyval_to_string(unsigned int keyval, unsigned int state, char_u *string) else string[0] = uc; len = 1; + + if (string[0] != uc) + // The modifier was used, remove it. + *state = *state & ~GDK_CONTROL_MASK; } else { @@ -1169,7 +1173,7 @@ key_press_event(GtkWidget *widget UNUSED, else #endif { - len = keyval_to_string(key_sym, state, string2); + 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. @@ -1212,39 +1216,9 @@ key_press_event(GtkWidget *widget UNUSED, 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 , 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; - } - } + // We used to apply Alt/Meta to the key here (Mod1Mask), but that is now + // done later, the same as it happens for the terminal. Hopefully that + // works for everybody... // Check for special keys. Also do this when len == 1 (key has an ASCII // value) to detect backspace, delete and keypad keys. @@ -1266,52 +1240,37 @@ key_press_event(GtkWidget *widget UNUSED, 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 - ))) + // Handle modifiers. + 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)) { - modifiers = modifiers_gdk2vim(state); + string[0] = CSI; + string[1] = K_SECOND(key); + string[2] = K_THIRD(key); + len = 3; + } + else + { + string[0] = key; + len = 1; + } - /* - * 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 (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) diff --git a/src/gui_haiku.cc b/src/gui_haiku.cc index b7ecf64402..78ca7b27ad 100644 --- a/src/gui_haiku.cc +++ b/src/gui_haiku.cc @@ -2,7 +2,7 @@ * * VIM - Vi IMproved by Bram Moolenaar * BeBox GUI support Copyright 1998 by Olaf Seibert. - * All Rights Reserved. + * All Rights Reserved. * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. @@ -79,7 +79,7 @@ extern "C" { #include "proto.h" #include "version.h" -} // extern "C" +} // extern "C" // ---------------- start of header part ---------------- @@ -143,165 +143,165 @@ extern int main(int argc, char **argv); // VimApp seems comparable to the X "vimShell" class VimApp: public BApplication { - typedef BApplication Inherited; - public: - VimApp(const char *appsig); - ~VimApp(); + typedef BApplication Inherited; + public: + VimApp(const char *appsig); + ~VimApp(); - // callbacks: + // callbacks: #if 0 - virtual void DispatchMessage(BMessage *m, BHandler *h) - { - m->PrintToStream(); - Inherited::DispatchMessage(m, h); - } + virtual void DispatchMessage(BMessage *m, BHandler *h) + { + m->PrintToStream(); + Inherited::DispatchMessage(m, h); + } #endif - virtual void ReadyToRun(); - virtual void ArgvReceived(int32 argc, char **argv); - virtual void RefsReceived(BMessage *m); - virtual bool QuitRequested(); - virtual void MessageReceived(BMessage *m); + virtual void ReadyToRun(); + virtual void ArgvReceived(int32 argc, char **argv); + virtual void RefsReceived(BMessage *m); + virtual bool QuitRequested(); + virtual void MessageReceived(BMessage *m); - static void SendRefs(BMessage *m, bool changedir); + static void SendRefs(BMessage *m, bool changedir); - sem_id fFilePanelSem; - BFilePanel* fFilePanel; - BPath fBrowsedPath; - private: + sem_id fFilePanelSem; + BFilePanel* fFilePanel; + BPath fBrowsedPath; + private: }; class VimWindow: public BWindow { - typedef BWindow Inherited; - public: - VimWindow(); - ~VimWindow(); + typedef BWindow Inherited; + public: + VimWindow(); + ~VimWindow(); - // virtual void DispatchMessage(BMessage *m, BHandler *h); - virtual void WindowActivated(bool active); - virtual bool QuitRequested(); + // virtual void DispatchMessage(BMessage *m, BHandler *h); + virtual void WindowActivated(bool active); + virtual bool QuitRequested(); - VimFormView *formView; + VimFormView *formView; - private: - void init(); + private: + void init(); }; class VimFormView: public BView { - typedef BView Inherited; - public: - VimFormView(BRect frame); - ~VimFormView(); + typedef BView Inherited; + public: + VimFormView(BRect frame); + ~VimFormView(); - // callbacks: - virtual void AllAttached(); - virtual void FrameResized(float new_width, float new_height); + // callbacks: + virtual void AllAttached(); + virtual void FrameResized(float new_width, float new_height); #define MENUBAR_MARGIN 1 - float MenuHeight() const - { return menuBar ? menuBar->Frame().Height() + MENUBAR_MARGIN: 0; } - BMenuBar *MenuBar() const - { return menuBar; } + float MenuHeight() const + { return menuBar ? menuBar->Frame().Height() + MENUBAR_MARGIN: 0; } + BMenuBar *MenuBar() const + { return menuBar; } - private: - void init(BRect); + private: + void init(BRect); - BMenuBar *menuBar; - VimTextAreaView *textArea; + BMenuBar *menuBar; + VimTextAreaView *textArea; #ifdef FEAT_TOOLBAR - public: - float ToolbarHeight() const; - VimToolbar *ToolBar() const - { return toolBar; } - private: - VimToolbar *toolBar; + public: + float ToolbarHeight() const; + VimToolbar *ToolBar() const + { return toolBar; } + private: + VimToolbar *toolBar; #endif #ifdef FEAT_GUI_TABLINE - public: - VimTabLine *TabLine() const { return tabLine; } - bool IsShowingTabLine() const { return showingTabLine; } - void SetShowingTabLine(bool showing) { showingTabLine = showing; } - float TablineHeight() const; - private: - VimTabLine *tabLine; - int showingTabLine; + public: + VimTabLine *TabLine() const { return tabLine; } + bool IsShowingTabLine() const { return showingTabLine; } + void SetShowingTabLine(bool showing) { showingTabLine = showing; } + float TablineHeight() const; + private: + VimTabLine *tabLine; + int showingTabLine; #endif }; class VimTextAreaView: public BView { - typedef BView Inherited; - public: - VimTextAreaView(BRect frame); - ~VimTextAreaView(); + typedef BView Inherited; + public: + VimTextAreaView(BRect frame); + ~VimTextAreaView(); - // callbacks: - virtual void Draw(BRect updateRect); - virtual void KeyDown(const char *bytes, int32 numBytes); - virtual void MouseDown(BPoint point); - virtual void MouseUp(BPoint point); - virtual void MouseMoved(BPoint point, uint32 transit, const BMessage *message); - virtual void MessageReceived(BMessage *m); + // callbacks: + virtual void Draw(BRect updateRect); + virtual void KeyDown(const char *bytes, int32 numBytes); + virtual void MouseDown(BPoint point); + virtual void MouseUp(BPoint point); + virtual void MouseMoved(BPoint point, uint32 transit, const BMessage *message); + virtual void MessageReceived(BMessage *m); - // own functions: - int mchInitFont(char_u *name); - void mchDrawString(int row, int col, char_u *s, int len, int flags); - void mchClearBlock(int row1, int col1, int row2, int col2); - void mchClearAll(); - void mchDeleteLines(int row, int num_lines); - void mchInsertLines(int row, int num_lines); + // own functions: + int mchInitFont(char_u *name); + void mchDrawString(int row, int col, char_u *s, int len, int flags); + void mchClearBlock(int row1, int col1, int row2, int col2); + void mchClearAll(); + void mchDeleteLines(int row, int num_lines); + void mchInsertLines(int row, int num_lines); - static void guiSendMouseEvent(int button, int x, int y, int repeated_click, int_u modifiers); - static void guiMouseMoved(int x, int y); - static void guiBlankMouse(bool should_hide); - static int_u mouseModifiersToVim(int32 beModifiers); + static void guiSendMouseEvent(int button, int x, int y, int repeated_click, int_u modifiers); + static void guiMouseMoved(int x, int y); + static void guiBlankMouse(bool should_hide); + static int_u mouseModifiersToVim(int32 beModifiers); - int32 mouseDragEventCount; + int32 mouseDragEventCount; #ifdef FEAT_MBYTE_IME - void DrawIMString(void); + void DrawIMString(void); #endif - private: - void init(BRect); + private: + void init(BRect); - int_u vimMouseButton; - int_u vimMouseModifiers; + int_u vimMouseButton; + int_u vimMouseModifiers; #ifdef FEAT_MBYTE_IME - struct { - BMessenger* messenger; - BMessage* message; - BPoint location; - int row; - int col; - int count; - } IMData; + struct { + BMessenger* messenger; + BMessage* message; + BPoint location; + int row; + int col; + int count; + } IMData; #endif }; class VimScrollBar: public BScrollBar { - typedef BScrollBar Inherited; - public: - VimScrollBar(scrollbar_T *gsb, orientation posture); - ~VimScrollBar(); + typedef BScrollBar Inherited; + public: + VimScrollBar(scrollbar_T *gsb, orientation posture); + ~VimScrollBar(); - virtual void ValueChanged(float newValue); - virtual void MouseUp(BPoint where); - void SetValue(float newval); - scrollbar_T *getGsb() - { return gsb; } + virtual void ValueChanged(float newValue); + virtual void MouseUp(BPoint where); + void SetValue(float newval); + scrollbar_T *getGsb() + { return gsb; } - int32 scrollEventCount; + int32 scrollEventCount; - private: - scrollbar_T *gsb; - float ignoreValue; + private: + scrollbar_T *gsb; + float ignoreValue; }; @@ -309,28 +309,28 @@ class VimScrollBar: public BScrollBar class VimToolbar : public BBox { - static BBitmap *normalButtonsBitmap; - static BBitmap *grayedButtonsBitmap; + static BBitmap *normalButtonsBitmap; + static BBitmap *grayedButtonsBitmap; - BBitmap *LoadVimBitmap(const char* fileName); - bool GetPictureFromBitmap(BPicture *pictureTo, int32 index, BBitmap *bitmapFrom, bool pressed); - bool ModifyBitmapToGrayed(BBitmap *bitmap); + BBitmap *LoadVimBitmap(const char* fileName); + bool GetPictureFromBitmap(BPicture *pictureTo, int32 index, BBitmap *bitmapFrom, bool pressed); + bool ModifyBitmapToGrayed(BBitmap *bitmap); - BList fButtonsList; - void InvalidateLayout(); + BList fButtonsList; + void InvalidateLayout(); - public: - VimToolbar(BRect frame, const char * name); - ~VimToolbar(); + public: + VimToolbar(BRect frame, const char * name); + ~VimToolbar(); - bool PrepareButtonBitmaps(); + bool PrepareButtonBitmaps(); - bool AddButton(int32 index, vimmenu_T *menu); - bool RemoveButton(vimmenu_T *menu); - bool GrayButton(vimmenu_T *menu, int grey); + bool AddButton(int32 index, vimmenu_T *menu); + bool RemoveButton(vimmenu_T *menu); + bool GrayButton(vimmenu_T *menu, int grey); - float ToolbarHeight() const; - virtual void AttachedToWindow(); + float ToolbarHeight() const; + virtual void AttachedToWindow(); }; BBitmap *VimToolbar::normalButtonsBitmap = NULL; @@ -345,19 +345,19 @@ const float ButtonMargin = 3.; class VimTabLine : public BTabView { - public: - class VimTab : public BTab { - public: - VimTab() : BTab(new BView(BRect(), "-Empty-", 0, 0)) {} + public: + class VimTab : public BTab { + public: + VimTab() : BTab(new BView(BRect(), "-Empty-", 0, 0)) {} - virtual void Select(BView* owner); - }; + virtual void Select(BView* owner); + }; - VimTabLine(BRect r) : BTabView(r, "vimTabLine", B_WIDTH_FROM_LABEL, - B_FOLLOW_LEFT | B_FOLLOW_TOP | B_FOLLOW_RIGHT, B_WILL_DRAW | B_FRAME_EVENTS) {} + VimTabLine(BRect r) : BTabView(r, "vimTabLine", B_WIDTH_FROM_LABEL, + B_FOLLOW_LEFT | B_FOLLOW_TOP | B_FOLLOW_RIGHT, B_WILL_DRAW | B_FRAME_EVENTS) {} - float TablineHeight() const; - virtual void MouseDown(BPoint point); + float TablineHeight() const; + virtual void MouseDown(BPoint point); }; #endif //FEAT_GUI_TABLINE @@ -367,97 +367,97 @@ class VimTabLine : public BTabView // Vim seems rather sloppy in this regard. class VimFont: public BFont { - typedef BFont Inherited; - public: - VimFont(); - VimFont(const VimFont *rhs); - VimFont(const BFont *rhs); - VimFont(const VimFont &rhs); - ~VimFont(); + typedef BFont Inherited; + public: + VimFont(); + VimFont(const VimFont *rhs); + VimFont(const BFont *rhs); + VimFont(const VimFont &rhs); + ~VimFont(); - VimFont *next; - int refcount; - char_u *name; + VimFont *next; + int refcount; + char_u *name; - private: - void init(); + private: + void init(); }; #if defined(FEAT_GUI_DIALOG) class VimDialog : public BWindow { - typedef BWindow Inherited; + typedef BWindow Inherited; - BButton* _CreateButton(int32 which, const char* label); + BButton* _CreateButton(int32 which, const char* label); + + public: + + class View : public BView { + typedef BView Inherited; public: + View(BRect frame); + ~View(); - class View : public BView { - typedef BView Inherited; - - public: - View(BRect frame); - ~View(); - - virtual void Draw(BRect updateRect); - void InitIcon(int32 type); - - private: - BBitmap* fIconBitmap; - }; - - VimDialog(int type, const char *title, const char *message, - const char *buttons, int dfltbutton, const char *textfield, - int ex_cmd); - ~VimDialog(); - - int Go(); - - virtual void MessageReceived(BMessage *msg); + virtual void Draw(BRect updateRect); + void InitIcon(int32 type); private: - sem_id fDialogSem; - int fDialogValue; - BList fButtonsList; - BTextView* fMessageView; - BTextControl* fInputControl; - const char* fInputValue; + BBitmap* fIconBitmap; + }; + + VimDialog(int type, const char *title, const char *message, + const char *buttons, int dfltbutton, const char *textfield, + int ex_cmd); + ~VimDialog(); + + int Go(); + + virtual void MessageReceived(BMessage *msg); + + private: + sem_id fDialogSem; + int fDialogValue; + BList fButtonsList; + BTextView* fMessageView; + BTextControl* fInputControl; + const char* fInputValue; }; class VimSelectFontDialog : public BWindow { - typedef BWindow Inherited; + typedef BWindow Inherited; - void _CleanList(BListView* list); - void _UpdateFontStyles(); - void _UpdateSizeInputPreview(); - void _UpdateFontPreview(); - bool _UpdateFromListItem(BListView* list, char* text, int textSize); - public: + void _CleanList(BListView* list); + void _UpdateFontStyles(); + void _UpdateSizeInputPreview(); + void _UpdateFontPreview(); + bool _UpdateFromListItem(BListView* list, char* text, int textSize); + public: - VimSelectFontDialog(font_family* family, font_style* style, float* size); - ~VimSelectFontDialog(); + VimSelectFontDialog(font_family* family, font_style* style, float* size); + ~VimSelectFontDialog(); - bool Go(); + bool Go(); - virtual void MessageReceived(BMessage *msg); + virtual void MessageReceived(BMessage *msg); - private: - status_t fStatus; - sem_id fDialogSem; - bool fDialogValue; - font_family* fFamily; - font_style* fStyle; - float* fSize; - font_family fFontFamily; - font_style fFontStyle; - float fFontSize; - BStringView* fPreview; - BListView* fFamiliesList; - BListView* fStylesList; - BListView* fSizesList; - BTextControl* fSizesInput; + private: + status_t fStatus; + sem_id fDialogSem; + bool fDialogValue; + font_family* fFamily; + font_style* fStyle; + float* fSize; + font_family fFontFamily; + font_style fFontStyle; + float fFontSize; + BStringView* fPreview; + BListView* fFamiliesList; + BListView* fStylesList; + BListView* fSizesList; + BTextControl* fSizesInput; }; #endif // FEAT_GUI_DIALOG @@ -465,8 +465,8 @@ class VimSelectFontDialog : public BWindow // ---------------- end of GUI classes ---------------- struct MainArgs { - int argc; - char **argv; + int argc; + char **argv; }; // These messages are copied through the VDCMP. @@ -480,177 +480,177 @@ struct MainArgs { #endif struct VimKeyMsg { - char_u length; - char_u chars[KEY_MSG_BUFSIZ]; // contains Vim encoding - bool csi_escape; + char_u length; + char_u chars[KEY_MSG_BUFSIZ]; // contains Vim encoding + bool csi_escape; }; struct VimResizeMsg { - int width; - int height; + int width; + int height; }; struct VimScrollBarMsg { - VimScrollBar *sb; - long value; - int stillDragging; + VimScrollBar *sb; + long value; + int stillDragging; }; struct VimMenuMsg { - vimmenu_T *guiMenu; + vimmenu_T *guiMenu; }; struct VimMouseMsg { - int button; - int x; - int y; - int repeated_click; - int_u modifiers; + int button; + int x; + int y; + int repeated_click; + int_u modifiers; }; struct VimMouseMovedMsg { - int x; - int y; + int x; + int y; }; struct VimFocusMsg { - bool active; + bool active; }; struct VimRefsMsg { - BMessage *message; - bool changedir; + BMessage *message; + bool changedir; }; struct VimTablineMsg { - int index; + int index; }; struct VimTablineMenuMsg { - int index; - int event; + int index; + int event; }; struct VimMsg { - enum VimMsgType { - Key, Resize, ScrollBar, Menu, Mouse, MouseMoved, Focus, Refs, Tabline, TablineMenu - }; + enum VimMsgType { + Key, Resize, ScrollBar, Menu, Mouse, MouseMoved, Focus, Refs, Tabline, TablineMenu + }; - union { - struct VimKeyMsg Key; - struct VimResizeMsg NewSize; - struct VimScrollBarMsg Scroll; - struct VimMenuMsg Menu; - struct VimMouseMsg Mouse; - struct VimMouseMovedMsg MouseMoved; - struct VimFocusMsg Focus; - struct VimRefsMsg Refs; - struct VimTablineMsg Tabline; - struct VimTablineMenuMsg TablineMenu; - } u; + union { + struct VimKeyMsg Key; + struct VimResizeMsg NewSize; + struct VimScrollBarMsg Scroll; + struct VimMenuMsg Menu; + struct VimMouseMsg Mouse; + struct VimMouseMovedMsg MouseMoved; + struct VimFocusMsg Focus; + struct VimRefsMsg Refs; + struct VimTablineMsg Tabline; + struct VimTablineMenuMsg TablineMenu; + } u; }; #define RGB(r, g, b) ((char_u)(r) << 16 | (char_u)(g) << 8 | (char_u)(b) << 0) -#define GUI_TO_RGB(g) { (g) >> 16, (g) >> 8, (g) >> 0, 255 } +#define GUI_TO_RGB(g) { (char_u)((g) >> 16), (char_u)((g) >> 8), (char_u)((g) >> 0), 255 } // ---------------- end of header part ---------------- static struct specialkey { - uint16 BeKeys; -#define KEY(a,b) ((a)<<8|(b)) -#define K(a) KEY(0,a) // for ASCII codes -#define F(b) KEY(1,b) // for scancodes - char_u vim_code0; - char_u vim_code1; + uint16 BeKeys; +#define KEY(a,b) ((a)<<8|(b)) +#define K(a) KEY(0,a) // for ASCII codes +#define F(b) KEY(1,b) // for scancodes + char_u vim_code0; + char_u vim_code1; } special_keys[] = { - {K(B_UP_ARROW), 'k', 'u'}, - {K(B_DOWN_ARROW), 'k', 'd'}, - {K(B_LEFT_ARROW), 'k', 'l'}, - {K(B_RIGHT_ARROW), 'k', 'r'}, - {K(B_BACKSPACE), 'k', 'b'}, - {K(B_INSERT), 'k', 'I'}, - {K(B_DELETE), 'k', 'D'}, - {K(B_HOME), 'k', 'h'}, - {K(B_END), '@', '7'}, - {K(B_PAGE_UP), 'k', 'P'}, // XK_Prior - {K(B_PAGE_DOWN), 'k', 'N'}, // XK_Next, + {K(B_UP_ARROW), 'k', 'u'}, + {K(B_DOWN_ARROW), 'k', 'd'}, + {K(B_LEFT_ARROW), 'k', 'l'}, + {K(B_RIGHT_ARROW), 'k', 'r'}, + {K(B_BACKSPACE), 'k', 'b'}, + {K(B_INSERT), 'k', 'I'}, + {K(B_DELETE), 'k', 'D'}, + {K(B_HOME), 'k', 'h'}, + {K(B_END), '@', '7'}, + {K(B_PAGE_UP), 'k', 'P'}, // XK_Prior + {K(B_PAGE_DOWN), 'k', 'N'}, // XK_Next, #define FIRST_FUNCTION_KEY 11 - {F(B_F1_KEY), 'k', '1'}, - {F(B_F2_KEY), 'k', '2'}, - {F(B_F3_KEY), 'k', '3'}, - {F(B_F4_KEY), 'k', '4'}, - {F(B_F5_KEY), 'k', '5'}, - {F(B_F6_KEY), 'k', '6'}, - {F(B_F7_KEY), 'k', '7'}, - {F(B_F8_KEY), 'k', '8'}, - {F(B_F9_KEY), 'k', '9'}, - {F(B_F10_KEY), 'k', ';'}, + {F(B_F1_KEY), 'k', '1'}, + {F(B_F2_KEY), 'k', '2'}, + {F(B_F3_KEY), 'k', '3'}, + {F(B_F4_KEY), 'k', '4'}, + {F(B_F5_KEY), 'k', '5'}, + {F(B_F6_KEY), 'k', '6'}, + {F(B_F7_KEY), 'k', '7'}, + {F(B_F8_KEY), 'k', '8'}, + {F(B_F9_KEY), 'k', '9'}, + {F(B_F10_KEY), 'k', ';'}, - {F(B_F11_KEY), 'F', '1'}, - {F(B_F12_KEY), 'F', '2'}, - // {XK_F13, 'F', '3'}, // would be print screen - // sysreq - {F(0x0F), 'F', '4'}, // scroll lock - {F(0x10), 'F', '5'}, // pause/break - // {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 + {F(B_F11_KEY), 'F', '1'}, + {F(B_F12_KEY), 'F', '2'}, + // {XK_F13, 'F', '3'}, // would be print screen + // sysreq + {F(0x0F), 'F', '4'}, // scroll lock + {F(0x10), 'F', '5'}, // pause/break + // {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 - // {XK_Help, '%', '1'}, // XK_Help - {F(B_PRINT_KEY), '%', '9'}, + // {XK_Help, '%', '1'}, // XK_Help + {F(B_PRINT_KEY), '%', '9'}, #if 0 - // Keypad keys: - {F(0x48), 'k', 'l'}, // XK_KP_Left - {F(0x4A), 'k', 'r'}, // XK_KP_Right - {F(0x38), 'k', 'u'}, // XK_KP_Up - {F(0x59), 'k', 'd'}, // XK_KP_Down - {F(0x64), 'k', 'I'}, // XK_KP_Insert - {F(0x65), 'k', 'D'}, // XK_KP_Delete - {F(0x37), 'k', 'h'}, // XK_KP_Home - {F(0x58), '@', '7'}, // XK_KP_End - {F(0x39), 'k', 'P'}, // XK_KP_Prior - {F(0x60), 'k', 'N'}, // XK_KP_Next - {F(0x49), '&', '8'}, // XK_Undo, keypad 5 + // Keypad keys: + {F(0x48), 'k', 'l'}, // XK_KP_Left + {F(0x4A), 'k', 'r'}, // XK_KP_Right + {F(0x38), 'k', 'u'}, // XK_KP_Up + {F(0x59), 'k', 'd'}, // XK_KP_Down + {F(0x64), 'k', 'I'}, // XK_KP_Insert + {F(0x65), 'k', 'D'}, // XK_KP_Delete + {F(0x37), 'k', 'h'}, // XK_KP_Home + {F(0x58), '@', '7'}, // XK_KP_End + {F(0x39), 'k', 'P'}, // XK_KP_Prior + {F(0x60), 'k', 'N'}, // XK_KP_Next + {F(0x49), '&', '8'}, // XK_Undo, keypad 5 #endif - // End of list marker: - {0, 0, 0} + // End of list marker: + {0, 0, 0} }; #define NUM_SPECIAL_KEYS (sizeof(special_keys)/sizeof(special_keys[0])) // ---------------- VimApp ---------------- - static void + static void docd(BPath &path) { - mch_chdir((char *)path.Path()); - // Do this to get the side effects of a :cd command - do_cmdline_cmd((char_u *)"cd ."); + mch_chdir((char *)path.Path()); + // Do this to get the side effects of a :cd command + do_cmdline_cmd((char_u *)"cd ."); } - static void + static void drop_callback(void *cookie) { // TODO here we could handle going to a specific position in the dropped @@ -660,119 +660,119 @@ drop_callback(void *cookie) } // Really handle dropped files and folders. - static void + static void RefsReceived(BMessage *m, bool changedir) { - uint32 type; - int32 count; + uint32 type; + int32 count; - m->PrintToStream(); - switch (m->what) { - case B_REFS_RECEIVED: - case B_SIMPLE_DATA: - m->GetInfo("refs", &type, &count); - if (type != B_REF_TYPE) - goto bad; - break; - case B_ARGV_RECEIVED: - m->GetInfo("argv", &type, &count); - if (type != B_STRING_TYPE) - goto bad; - if (changedir) { - char *dirname; - if (m->FindString("cwd", (const char **) &dirname) == B_OK) { - chdir(dirname); - do_cmdline_cmd((char_u *)"cd ."); - } - } - break; - default: + m->PrintToStream(); + switch (m->what) { + case B_REFS_RECEIVED: + case B_SIMPLE_DATA: + m->GetInfo("refs", &type, &count); + if (type != B_REF_TYPE) + goto bad; + break; + case B_ARGV_RECEIVED: + m->GetInfo("argv", &type, &count); + if (type != B_STRING_TYPE) + goto bad; + if (changedir) { + char *dirname; + if (m->FindString("cwd", (const char **) &dirname) == B_OK) { + chdir(dirname); + do_cmdline_cmd((char_u *)"cd ."); + } + } + break; + default: bad: - /*fprintf(stderr, "bad!\n"); */ - delete m; - return; - } + /*fprintf(stderr, "bad!\n"); */ + delete m; + return; + } #ifdef FEAT_VISUAL - reset_VIsual(); + reset_VIsual(); #endif - char_u **fnames; - fnames = (char_u **) alloc(count * sizeof(char_u *)); - int fname_index = 0; + char_u **fnames; + fnames = (char_u **) alloc(count * sizeof(char_u *)); + int fname_index = 0; - switch (m->what) { - case B_REFS_RECEIVED: - case B_SIMPLE_DATA: - // fprintf(stderr, "case B_REFS_RECEIVED\n"); - for (int i = 0; i < count; ++i) - { - entry_ref ref; - if (m->FindRef("refs", i, &ref) == B_OK) { - BEntry entry(&ref, false); - BPath path; - entry.GetPath(&path); + switch (m->what) { + case B_REFS_RECEIVED: + case B_SIMPLE_DATA: + // fprintf(stderr, "case B_REFS_RECEIVED\n"); + for (int i = 0; i < count; ++i) + { + entry_ref ref; + if (m->FindRef("refs", i, &ref) == B_OK) { + BEntry entry(&ref, false); + BPath path; + entry.GetPath(&path); - // Change to parent directory? - if (changedir) { - BPath parentpath; - path.GetParent(&parentpath); - docd(parentpath); - } + // Change to parent directory? + if (changedir) { + BPath parentpath; + path.GetParent(&parentpath); + docd(parentpath); + } - // Is it a directory? If so, cd into it. - BDirectory bdir(&ref); - if (bdir.InitCheck() == B_OK) { - // don't cd if we already did it - if (!changedir) - docd(path); - } else { - mch_dirname(IObuff, IOSIZE); - char_u *fname = shorten_fname((char_u *)path.Path(), IObuff); - if (fname == NULL) - fname = (char_u *)path.Path(); - fnames[fname_index++] = vim_strsave(fname); - // fprintf(stderr, "%s\n", fname); - } + // Is it a directory? If so, cd into it. + BDirectory bdir(&ref); + if (bdir.InitCheck() == B_OK) { + // don't cd if we already did it + if (!changedir) + docd(path); + } else { + mch_dirname(IObuff, IOSIZE); + char_u *fname = shorten_fname((char_u *)path.Path(), IObuff); + if (fname == NULL) + fname = (char_u *)path.Path(); + fnames[fname_index++] = vim_strsave(fname); + // fprintf(stderr, "%s\n", fname); + } - // Only do it for the first file/dir - changedir = false; - } - } - break; - case B_ARGV_RECEIVED: - // fprintf(stderr, "case B_ARGV_RECEIVED\n"); - for (int i = 1; i < count; ++i) - { - char *fname; + // Only do it for the first file/dir + changedir = false; + } + } + break; + case B_ARGV_RECEIVED: + // fprintf(stderr, "case B_ARGV_RECEIVED\n"); + for (int i = 1; i < count; ++i) + { + char *fname; - if (m->FindString("argv", i, (const char **) &fname) == B_OK) { - fnames[fname_index++] = vim_strsave((char_u *)fname); - } - } - break; - default: - // fprintf(stderr, "case default\n"); - break; - } + if (m->FindString("argv", i, (const char **) &fname) == B_OK) { + fnames[fname_index++] = vim_strsave((char_u *)fname); + } + } + break; + default: + // fprintf(stderr, "case default\n"); + break; + } - delete m; + delete m; - // Handle the drop, :edit to get to the file - if (fname_index > 0) { - handle_drop(fname_index, fnames, FALSE, drop_callback, NULL); + // Handle the drop, :edit to get to the file + if (fname_index > 0) { + handle_drop(fname_index, fnames, FALSE, drop_callback, NULL); - setcursor(); - out_flush(); - } else { - vim_free(fnames); - } + setcursor(); + out_flush(); + } else { + vim_free(fnames); + } } VimApp::VimApp(const char *appsig): - BApplication(appsig), - fFilePanelSem(-1), - fFilePanel(NULL) + BApplication(appsig), + fFilePanelSem(-1), + fFilePanel(NULL) { } @@ -780,1073 +780,1074 @@ VimApp::~VimApp() { } - void + void VimApp::ReadyToRun() { - /* - * Apparently signals are inherited by the created thread - - * disable the most annoying ones. - */ - signal(SIGINT, SIG_IGN); - signal(SIGQUIT, SIG_IGN); + /* + * Apparently signals are inherited by the created thread - + * disable the most annoying ones. + */ + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); } - void + void VimApp::ArgvReceived(int32 arg_argc, char **arg_argv) { - if (!IsLaunching()) { - /* - * This can happen if we are set to Single or Exclusive - * Launch. Be nice and open the file(s). - */ - if (gui.vimWindow) - gui.vimWindow->Minimize(false); - BMessage *m = CurrentMessage(); - DetachCurrentMessage(); - SendRefs(m, true); - } -} - - void -VimApp::RefsReceived(BMessage *m) -{ - // Horrible hack!!! XXX XXX XXX - // The real problem is that b_start_ffc is set too late for - // the initial empty buffer. As a result the window will be - // split instead of abandoned. - int limit = 15; - while (--limit >= 0 && (curbuf == NULL || curbuf->b_start_ffc == 0)) - snooze(100000); // 0.1 s + if (!IsLaunching()) { + /* + * This can happen if we are set to Single or Exclusive + * Launch. Be nice and open the file(s). + */ if (gui.vimWindow) - gui.vimWindow->Minimize(false); + gui.vimWindow->Minimize(false); + BMessage *m = CurrentMessage(); DetachCurrentMessage(); SendRefs(m, true); + } +} + + void +VimApp::RefsReceived(BMessage *m) +{ + // Horrible hack!!! XXX XXX XXX + // The real problem is that b_start_ffc is set too late for + // the initial empty buffer. As a result the window will be + // split instead of abandoned. + int limit = 15; + while (--limit >= 0 && (curbuf == NULL || curbuf->b_start_ffc == 0)) + snooze(100000); // 0.1 s + if (gui.vimWindow) + gui.vimWindow->Minimize(false); + DetachCurrentMessage(); + SendRefs(m, true); } /* * Pass a BMessage on to the main() thread. * Caller must have detached the message. */ - void + void VimApp::SendRefs(BMessage *m, bool changedir) { - VimRefsMsg rm; - rm.message = m; - rm.changedir = changedir; + VimRefsMsg rm; + rm.message = m; + rm.changedir = changedir; - write_port(gui.vdcmp, VimMsg::Refs, &rm, sizeof(rm)); - // calls ::RefsReceived + write_port(gui.vdcmp, VimMsg::Refs, &rm, sizeof(rm)); + // calls ::RefsReceived } - void + void VimApp::MessageReceived(BMessage *m) { - switch (m->what) { - case 'save': - { - entry_ref refDirectory; - m->FindRef("directory", &refDirectory); - fBrowsedPath.SetTo(&refDirectory); - BString strName; - m->FindString("name", &strName); - fBrowsedPath.Append(strName.String()); - } - break; - case 'open': - { - entry_ref ref; - m->FindRef("refs", &ref); - fBrowsedPath.SetTo(&ref); - } - break; - case B_CANCEL: - { - BFilePanel *panel; - m->FindPointer("source", (void**)&panel); - if(fFilePanelSem != -1 && panel == fFilePanel) - { - delete_sem(fFilePanelSem); - fFilePanelSem = -1; - } + switch (m->what) { + case 'save': + { + entry_ref refDirectory; + m->FindRef("directory", &refDirectory); + fBrowsedPath.SetTo(&refDirectory); + BString strName; + m->FindString("name", &strName); + fBrowsedPath.Append(strName.String()); + } + break; + case 'open': + { + entry_ref ref; + m->FindRef("refs", &ref); + fBrowsedPath.SetTo(&ref); + } + break; + case B_CANCEL: + { + BFilePanel *panel; + m->FindPointer("source", (void**)&panel); + if (fFilePanelSem != -1 && panel == fFilePanel) + { + delete_sem(fFilePanelSem); + fFilePanelSem = -1; + } - } - break; - default: - Inherited::MessageReceived(m); - break; - } + } + break; + default: + Inherited::MessageReceived(m); + break; + } } - bool + bool VimApp::QuitRequested() { - (void)Inherited::QuitRequested(); - return false; + (void)Inherited::QuitRequested(); + return false; } // ---------------- VimWindow ---------------- VimWindow::VimWindow(): - BWindow(BRect(40, 40, 150, 150), - "Vim", - B_TITLED_WINDOW, - 0, - B_CURRENT_WORKSPACE) + BWindow(BRect(40, 40, 150, 150), + "Vim", + B_TITLED_WINDOW, + 0, + B_CURRENT_WORKSPACE) { - init(); + init(); } VimWindow::~VimWindow() { - if (formView) { - RemoveChild(formView); - delete formView; - } - gui.vimWindow = NULL; + if (formView) { + RemoveChild(formView); + delete formView; + } + gui.vimWindow = NULL; } - void + void VimWindow::init() { - // Attach the VimFormView - formView = new VimFormView(Bounds()); - if (formView != NULL) { - AddChild(formView); - } + // Attach the VimFormView + formView = new VimFormView(Bounds()); + if (formView != NULL) { + AddChild(formView); + } } #if 0 // disabled in zeta patch - void + void VimWindow::DispatchMessage(BMessage *m, BHandler *h) { - /* - * Route B_MOUSE_UP messages to MouseUp(), in - * a manner that should be compatible with the - * intended future system behaviour. - */ - switch (m->what) { - case B_MOUSE_UP: - // if (!h) h = PreferredHandler(); - // gcc isn't happy without this extra set of braces, complains about - // jump to case label crosses init of 'class BView * v' - // richard@whitequeen.com jul 99 - { - BView *v = dynamic_cast(h); - if (v) { - // m->PrintToStream(); - BPoint where; - m->FindPoint("where", &where); - v->MouseUp(where); - } else { - Inherited::DispatchMessage(m, h); - } - } - break; - default: - Inherited::DispatchMessage(m, h); - } + /* + * Route B_MOUSE_UP messages to MouseUp(), in + * a manner that should be compatible with the + * intended future system behaviour. + */ + switch (m->what) { + case B_MOUSE_UP: + // if (!h) h = PreferredHandler(); + // gcc isn't happy without this extra set of braces, complains about + // jump to case label crosses init of 'class BView * v' + // richard@whitequeen.com jul 99 + { + BView *v = dynamic_cast(h); + if (v) { + // m->PrintToStream(); + BPoint where; + m->FindPoint("where", &where); + v->MouseUp(where); + } else { + Inherited::DispatchMessage(m, h); + } + } + break; + default: + Inherited::DispatchMessage(m, h); + } } #endif - void + void VimWindow::WindowActivated(bool active) { - Inherited::WindowActivated(active); - // the textArea gets the keyboard action - if (active && gui.vimTextArea) - gui.vimTextArea->MakeFocus(true); + Inherited::WindowActivated(active); + // the textArea gets the keyboard action + if (active && gui.vimTextArea) + gui.vimTextArea->MakeFocus(true); - struct VimFocusMsg fm; - fm.active = active; + struct VimFocusMsg fm; + fm.active = active; - write_port(gui.vdcmp, VimMsg::Focus, &fm, sizeof(fm)); + write_port(gui.vdcmp, VimMsg::Focus, &fm, sizeof(fm)); } - bool + bool VimWindow::QuitRequested() { - struct VimKeyMsg km; - km.length = 5; - memcpy((char *)km.chars, "\033:qa\r", km.length); - km.csi_escape = false; - write_port(gui.vdcmp, VimMsg::Key, &km, sizeof(km)); - return false; + struct VimKeyMsg km; + km.length = 5; + memcpy((char *)km.chars, "\033:qa\r", km.length); + km.csi_escape = false; + write_port(gui.vdcmp, VimMsg::Key, &km, sizeof(km)); + return false; } // ---------------- VimFormView ---------------- VimFormView::VimFormView(BRect frame): - BView(frame, "VimFormView", B_FOLLOW_ALL_SIDES, - B_WILL_DRAW | B_FRAME_EVENTS), - menuBar(NULL), + BView(frame, "VimFormView", B_FOLLOW_ALL_SIDES, + B_WILL_DRAW | B_FRAME_EVENTS), + menuBar(NULL), #ifdef FEAT_TOOLBAR - toolBar(NULL), + toolBar(NULL), #endif #ifdef FEAT_GUI_TABLINE -// showingTabLine(false), - tabLine(NULL), +// showingTabLine(false), + tabLine(NULL), #endif - textArea(NULL) + textArea(NULL) { - init(frame); + init(frame); } VimFormView::~VimFormView() { - if (menuBar) { - RemoveChild(menuBar); + if (menuBar) { + RemoveChild(menuBar); #ifdef never - // deleting the menuBar leads to SEGV on exit - // richard@whitequeen.com Jul 99 - delete menuBar; + // deleting the menuBar leads to SEGV on exit + // richard@whitequeen.com Jul 99 + delete menuBar; #endif - } + } #ifdef FEAT_TOOLBAR - delete toolBar; + delete toolBar; #endif #ifdef FEAT_GUI_TABLINE - delete tabLine; + delete tabLine; #endif - if (textArea) { - RemoveChild(textArea); - delete textArea; - } - gui.vimForm = NULL; + if (textArea) { + RemoveChild(textArea); + delete textArea; + } + gui.vimForm = NULL; } - void + void VimFormView::init(BRect frame) { - menuBar = new BMenuBar(BRect(0,0,-MENUBAR_MARGIN,-MENUBAR_MARGIN), - "VimMenuBar"); + menuBar = new BMenuBar(BRect(0,0,-MENUBAR_MARGIN,-MENUBAR_MARGIN), + "VimMenuBar"); - AddChild(menuBar); + AddChild(menuBar); #ifdef FEAT_TOOLBAR - toolBar = new VimToolbar(BRect(0,0,0,0), "VimToolBar"); - toolBar->PrepareButtonBitmaps(); - AddChild(toolBar); + toolBar = new VimToolbar(BRect(0,0,0,0), "VimToolBar"); + toolBar->PrepareButtonBitmaps(); + AddChild(toolBar); #endif #ifdef FEAT_GUI_TABLINE - tabLine = new VimTabLine(BRect(0,0,0,0)); -// tabLine->PrepareButtonBitmaps(); - AddChild(tabLine); + tabLine = new VimTabLine(BRect(0,0,0,0)); +// tabLine->PrepareButtonBitmaps(); + AddChild(tabLine); #endif - BRect remaining = frame; - textArea = new VimTextAreaView(remaining); - AddChild(textArea); - // The textArea will be resized later when menus are added + BRect remaining = frame; + textArea = new VimTextAreaView(remaining); + AddChild(textArea); + // The textArea will be resized later when menus are added - gui.vimForm = this; + gui.vimForm = this; } #ifdef FEAT_TOOLBAR - float + float VimFormView::ToolbarHeight() const { - return toolBar ? toolBar->ToolbarHeight() : 0.; + return toolBar ? toolBar->ToolbarHeight() : 0.; } #endif #ifdef FEAT_GUI_TABLINE - float + float VimFormView::TablineHeight() const { - return (tabLine && IsShowingTabLine()) ? tabLine->TablineHeight() : 0.; + return (tabLine && IsShowingTabLine()) ? tabLine->TablineHeight() : 0.; } #endif - void + void VimFormView::AllAttached() { - /* - * Apparently signals are inherited by the created thread - - * disable the most annoying ones. - */ - signal(SIGINT, SIG_IGN); - signal(SIGQUIT, SIG_IGN); + /* + * Apparently signals are inherited by the created thread - + * disable the most annoying ones. + */ + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); - if (menuBar && textArea) { - /* - * Resize the textArea to fill the space left over by the menu. - * This is somewhat futile since it will be done again once - * menus are added to the menu bar. - */ - BRect remaining = Bounds(); + if (menuBar && textArea) { + /* + * Resize the textArea to fill the space left over by the menu. + * This is somewhat futile since it will be done again once + * menus are added to the menu bar. + */ + BRect remaining = Bounds(); #ifdef FEAT_MENU - remaining.top += MenuHeight(); - menuBar->ResizeTo(remaining.right, remaining.top); - gui.menu_height = (int) MenuHeight(); + remaining.top += MenuHeight(); + menuBar->ResizeTo(remaining.right, remaining.top); + gui.menu_height = (int) MenuHeight(); #endif #ifdef FEAT_TOOLBAR - toolBar->MoveTo(remaining.left, remaining.top); - toolBar->ResizeTo(remaining.right, ToolbarHeight()); - remaining.top += ToolbarHeight(); - gui.toolbar_height = ToolbarHeight(); + toolBar->MoveTo(remaining.left, remaining.top); + toolBar->ResizeTo(remaining.right, ToolbarHeight()); + remaining.top += ToolbarHeight(); + gui.toolbar_height = ToolbarHeight(); #endif #ifdef FEAT_GUI_TABLINE - tabLine->MoveTo(remaining.left, remaining.top); - tabLine->ResizeTo(remaining.right + 1, TablineHeight()); - remaining.top += TablineHeight(); - gui.tabline_height = TablineHeight(); + tabLine->MoveTo(remaining.left, remaining.top); + tabLine->ResizeTo(remaining.right + 1, TablineHeight()); + remaining.top += TablineHeight(); + gui.tabline_height = TablineHeight(); #endif - textArea->ResizeTo(remaining.Width(), remaining.Height()); - textArea->MoveTo(remaining.left, remaining.top); - } + textArea->ResizeTo(remaining.Width(), remaining.Height()); + textArea->MoveTo(remaining.left, remaining.top); + } - Inherited::AllAttached(); + Inherited::AllAttached(); } - void + void VimFormView::FrameResized(float new_width, float new_height) { - struct VimResizeMsg sm; - int adjust_h, adjust_w; + struct VimResizeMsg sm; + int adjust_h, adjust_w; - new_width += 1; // adjust from width to number of pixels occupied - new_height += 1; + new_width += 1; // adjust from width to number of pixels occupied + new_height += 1; - sm.width = (int) new_width; - sm.height = (int) new_height; - adjust_w = ((int)new_width - gui_get_base_width()) % gui.char_width; - adjust_h = ((int)new_height - gui_get_base_height()) % gui.char_height; + sm.width = (int) new_width; + sm.height = (int) new_height; + adjust_w = ((int)new_width - gui_get_base_width()) % gui.char_width; + adjust_h = ((int)new_height - gui_get_base_height()) % gui.char_height; - if (adjust_w > 0 || adjust_h > 0) { - sm.width -= adjust_w; - sm.height -= adjust_h; - } + if (adjust_w > 0 || adjust_h > 0) { + sm.width -= adjust_w; + sm.height -= adjust_h; + } - write_port(gui.vdcmp, VimMsg::Resize, &sm, sizeof(sm)); - // calls gui_resize_shell(new_width, new_height); + write_port(gui.vdcmp, VimMsg::Resize, &sm, sizeof(sm)); + // calls gui_resize_shell(new_width, new_height); - return; + return; - /* - * The area below the vertical scrollbar is erased to the colour - * set with SetViewColor() automatically, because we had set - * B_WILL_DRAW. Resizing the window tight around the vertical - * scroll bar also helps to avoid debris. - */ + /* + * The area below the vertical scrollbar is erased to the colour + * set with SetViewColor() automatically, because we had set + * B_WILL_DRAW. Resizing the window tight around the vertical + * scroll bar also helps to avoid debris. + */ } // ---------------- VimTextAreaView ---------------- VimTextAreaView::VimTextAreaView(BRect frame): - BView(frame, "VimTextAreaView", B_FOLLOW_ALL_SIDES, + BView(frame, "VimTextAreaView", B_FOLLOW_ALL_SIDES, #ifdef FEAT_MBYTE_IME - B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_INPUT_METHOD_AWARE), + B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_INPUT_METHOD_AWARE #else - B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE), + B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE #endif - mouseDragEventCount(0) + ), + mouseDragEventCount(0) { #ifdef FEAT_MBYTE_IME - IMData.messenger = NULL; - IMData.message = NULL; + IMData.messenger = NULL; + IMData.message = NULL; #endif - init(frame); + init(frame); } VimTextAreaView::~VimTextAreaView() { - gui.vimTextArea = NULL; + gui.vimTextArea = NULL; } - void + void VimTextAreaView::init(BRect frame) { - // set up global var for fast access - gui.vimTextArea = this; + // set up global var for fast access + gui.vimTextArea = this; - /* - * Tell the app server not to erase the view: we will - * fill it in completely by ourselves. - * (Does this really work? Even if not, it won't harm either.) - */ - SetViewColor(B_TRANSPARENT_32_BIT); + /* + * Tell the app server not to erase the view: we will + * fill it in completely by ourselves. + * (Does this really work? Even if not, it won't harm either.) + */ + SetViewColor(B_TRANSPARENT_32_BIT); #define PEN_WIDTH 1 - SetPenSize(PEN_WIDTH); + SetPenSize(PEN_WIDTH); #define W_WIDTH(curwin) 0 } - void + void VimTextAreaView::Draw(BRect updateRect) { - /* - * XXX Other ports call here: - * out_flush(); * make sure all output has been processed * - * but we can't do that, since it involves too much information - * that is owned by other threads... - */ + /* + * XXX Other ports call here: + * out_flush(); * make sure all output has been processed * + * but we can't do that, since it involves too much information + * that is owned by other threads... + */ - /* - * No need to use gui.vimWindow->Lock(): we are locked already. - * However, it would not hurt. - */ - rgb_color rgb = GUI_TO_RGB(gui.back_pixel); - SetLowColor(rgb); - FillRect(updateRect, B_SOLID_LOW); - gui_redraw((int) updateRect.left, (int) updateRect.top, - (int) (updateRect.Width() + PEN_WIDTH), (int) (updateRect.Height() + PEN_WIDTH)); + /* + * No need to use gui.vimWindow->Lock(): we are locked already. + * However, it would not hurt. + */ + rgb_color rgb = GUI_TO_RGB(gui.back_pixel); + SetLowColor(rgb); + FillRect(updateRect, B_SOLID_LOW); + gui_redraw((int) updateRect.left, (int) updateRect.top, + (int) (updateRect.Width() + PEN_WIDTH), (int) (updateRect.Height() + PEN_WIDTH)); - // Clear the border areas if needed - SetLowColor(rgb); + // Clear the border areas if needed + SetLowColor(rgb); - if (updateRect.left < FILL_X(0)) // left border - FillRect(BRect(updateRect.left, updateRect.top, - FILL_X(0)-PEN_WIDTH, updateRect.bottom), B_SOLID_LOW); - if (updateRect.top < FILL_Y(0)) // top border - FillRect(BRect(updateRect.left, updateRect.top, - updateRect.right, FILL_Y(0)-PEN_WIDTH), B_SOLID_LOW); - if (updateRect.right >= FILL_X(Columns)) // right border - FillRect(BRect(FILL_X((int)Columns), updateRect.top, - updateRect.right, updateRect.bottom), B_SOLID_LOW); - if (updateRect.bottom >= FILL_Y(Rows)) // bottom border - FillRect(BRect(updateRect.left, FILL_Y((int)Rows), - updateRect.right, updateRect.bottom), B_SOLID_LOW); + if (updateRect.left < FILL_X(0)) // left border + FillRect(BRect(updateRect.left, updateRect.top, + FILL_X(0)-PEN_WIDTH, updateRect.bottom), B_SOLID_LOW); + if (updateRect.top < FILL_Y(0)) // top border + FillRect(BRect(updateRect.left, updateRect.top, + updateRect.right, FILL_Y(0)-PEN_WIDTH), B_SOLID_LOW); + if (updateRect.right >= FILL_X(Columns)) // right border + FillRect(BRect(FILL_X((int)Columns), updateRect.top, + updateRect.right, updateRect.bottom), B_SOLID_LOW); + if (updateRect.bottom >= FILL_Y(Rows)) // bottom border + FillRect(BRect(updateRect.left, FILL_Y((int)Rows), + updateRect.right, updateRect.bottom), B_SOLID_LOW); #ifdef FEAT_MBYTE_IME - DrawIMString(); + DrawIMString(); #endif } - void + void VimTextAreaView::KeyDown(const char *bytes, int32 numBytes) { - struct VimKeyMsg km; - char_u *dest = km.chars; + struct VimKeyMsg km; + char_u *dest = km.chars; - bool canHaveVimModifiers = false; + bool canHaveVimModifiers = false; - BMessage *msg = Window()->CurrentMessage(); - assert(msg); - // msg->PrintToStream(); + BMessage *msg = Window()->CurrentMessage(); + assert(msg); + // msg->PrintToStream(); + + /* + * Convert special keys to Vim codes. + * I think it is better to do it in the window thread + * so we use at least a little bit of the potential + * of our 2 CPUs. Besides, due to the fantastic mapping + * of special keys to UTF-8, we have quite some work to + * do... + * TODO: I'm not quite happy with detection of special + * keys. Perhaps I should use scan codes after all... + */ + if (numBytes > 1) { + // This cannot be a special key + if (numBytes > KEY_MSG_BUFSIZ) + numBytes = KEY_MSG_BUFSIZ; // should never happen... ??? + km.length = numBytes; + memcpy((char *)dest, bytes, numBytes); + km.csi_escape = true; + } else { + int32 scancode = 0; + msg->FindInt32("key", &scancode); + + int32 beModifiers = 0; + msg->FindInt32("modifiers", &beModifiers); + + char_u string[3]; + int len = 0; + km.length = 0; /* - * Convert special keys to Vim codes. - * I think it is better to do it in the window thread - * so we use at least a little bit of the potential - * of our 2 CPUs. Besides, due to the fantastic mapping - * of special keys to UTF-8, we have quite some work to - * do... - * TODO: I'm not quite happy with detection of special - * keys. Perhaps I should use scan codes after all... + * For normal, printable ASCII characters, don't look them up + * to check if they might be a special key. They aren't. */ - if (numBytes > 1) { - // This cannot be a special key - if (numBytes > KEY_MSG_BUFSIZ) - numBytes = KEY_MSG_BUFSIZ; // should never happen... ??? - km.length = numBytes; - memcpy((char *)dest, bytes, numBytes); - km.csi_escape = true; - } else { - int32 scancode = 0; - msg->FindInt32("key", &scancode); - - int32 beModifiers = 0; - msg->FindInt32("modifiers", &beModifiers); - - char_u string[3]; - int len = 0; - km.length = 0; + assert(B_BACKSPACE <= 0x20); + assert(B_DELETE == 0x7F); + if (((char_u)bytes[0] <= 0x20 || (char_u)bytes[0] == 0x7F) && + numBytes == 1) { + /* + * Due to the great nature of Be's mapping of special keys, + * viz. into the range of the control characters, + * we can only be sure it is *really* a special key if + * if it is special without using ctrl. So, only if ctrl is + * used, we need to check it unmodified. + */ + if (beModifiers & B_CONTROL_KEY) { + int index = keyMap->normal_map[scancode]; + int newNumBytes = keyMapChars[index]; + char_u *newBytes = (char_u *)&keyMapChars[index + 1]; /* - * For normal, printable ASCII characters, don't look them up - * to check if they might be a special key. They aren't. + * Check if still special without the control key. + * This is needed for BACKSPACE: that key does produce + * different values with modifiers (DEL). + * Otherwise we could simply have checked for equality. */ - assert(B_BACKSPACE <= 0x20); - assert(B_DELETE == 0x7F); - if (((char_u)bytes[0] <= 0x20 || (char_u)bytes[0] == 0x7F) && - numBytes == 1) { - /* - * Due to the great nature of Be's mapping of special keys, - * viz. into the range of the control characters, - * we can only be sure it is *really* a special key if - * if it is special without using ctrl. So, only if ctrl is - * used, we need to check it unmodified. - */ - if (beModifiers & B_CONTROL_KEY) { - int index = keyMap->normal_map[scancode]; - int newNumBytes = keyMapChars[index]; - char_u *newBytes = (char_u *)&keyMapChars[index + 1]; - - /* - * Check if still special without the control key. - * This is needed for BACKSPACE: that key does produce - * different values with modifiers (DEL). - * Otherwise we could simply have checked for equality. - */ - if (newNumBytes != 1 || (*newBytes > 0x20 && - *newBytes != 0x7F )) { - goto notspecial; - } - bytes = (char *)newBytes; - } - canHaveVimModifiers = true; - - uint16 beoskey; - int first, last; - - /* - * If numBytes == 0 that probably always indicates a special key. - * (does not happen yet) - */ - if (numBytes == 0 || bytes[0] == B_FUNCTION_KEY) { - beoskey = F(scancode); - first = FIRST_FUNCTION_KEY; - last = NUM_SPECIAL_KEYS; - } else if (*bytes == '\n' && scancode == 0x47) { - // remap the (non-keypad) ENTER key from \n to \r. - string[0] = '\r'; - len = 1; - first = last = 0; - } else { - beoskey = K(bytes[0]); - first = 0; - last = FIRST_FUNCTION_KEY; - } - - for (int i = first; i < last; i++) { - if (special_keys[i].BeKeys == beoskey) { - string[0] = CSI; - string[1] = special_keys[i].vim_code0; - string[2] = special_keys[i].vim_code1; - len = 3; - } - } + if (newNumBytes != 1 || (*newBytes > 0x20 && + *newBytes != 0x7F )) { + goto notspecial; } + bytes = (char *)newBytes; + } + canHaveVimModifiers = true; + + uint16 beoskey; + int first, last; + + /* + * If numBytes == 0 that probably always indicates a special key. + * (does not happen yet) + */ + if (numBytes == 0 || bytes[0] == B_FUNCTION_KEY) { + beoskey = F(scancode); + first = FIRST_FUNCTION_KEY; + last = NUM_SPECIAL_KEYS; + } else if (*bytes == '\n' && scancode == 0x47) { + // remap the (non-keypad) ENTER key from \n to \r. + string[0] = '\r'; + len = 1; + first = last = 0; + } else { + beoskey = K(bytes[0]); + first = 0; + last = FIRST_FUNCTION_KEY; + } + + for (int i = first; i < last; i++) { + if (special_keys[i].BeKeys == beoskey) { + string[0] = CSI; + string[1] = special_keys[i].vim_code0; + string[2] = special_keys[i].vim_code1; + len = 3; + } + } + } notspecial: - if (len == 0) { - string[0] = bytes[0]; - len = 1; + if (len == 0) { + string[0] = bytes[0]; + len = 1; + } + + // Special keys (and a few others) may have modifiers +#if 0 + if (len == 3 || + bytes[0] == B_SPACE || bytes[0] == B_TAB || + bytes[0] == B_RETURN || bytes[0] == '\r' || + bytes[0] == B_ESCAPE) +#else + if (canHaveVimModifiers) +#endif + { + int modifiers; + modifiers = 0; + if (beModifiers & B_SHIFT_KEY) + modifiers |= MOD_MASK_SHIFT; + if (beModifiers & B_CONTROL_KEY) + modifiers |= MOD_MASK_CTRL; + if (beModifiers & B_OPTION_KEY) + modifiers |= MOD_MASK_ALT; + + /* + * For some keys a shift modifier is translated into another key + * code. Do we need to handle the case where len != 1 and + * string[0] != CSI? (Not for BeOS, since len == 3 implies + * string[0] == CSI...) + */ + int key; + if (string[0] == CSI && len == 3) + key = TO_SPECIAL(string[1], string[2]); + else + key = string[0]; + key = simplify_key(key, &modifiers); + 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; } - // Special keys (and a few others) may have modifiers -#if 0 - if (len == 3 || - bytes[0] == B_SPACE || bytes[0] == B_TAB || - bytes[0] == B_RETURN || bytes[0] == '\r' || - bytes[0] == B_ESCAPE) -#else - if (canHaveVimModifiers) -#endif - { - int modifiers; - modifiers = 0; - if (beModifiers & B_SHIFT_KEY) - modifiers |= MOD_MASK_SHIFT; - if (beModifiers & B_CONTROL_KEY) - modifiers |= MOD_MASK_CTRL; - if (beModifiers & B_OPTION_KEY) - modifiers |= MOD_MASK_ALT; + if (modifiers) + { + *dest++ = CSI; + *dest++ = KS_MODIFIER; + *dest++ = modifiers; + km.length = 3; + } + } + memcpy((char *)dest, string, len); + km.length += len; + km.csi_escape = false; + } - /* - * For some keys a shift modifier is translated into another key - * code. Do we need to handle the case where len != 1 and - * string[0] != CSI? (Not for BeOS, since len == 3 implies - * string[0] == CSI...) - */ - int key; - if (string[0] == CSI && len == 3) - key = TO_SPECIAL(string[1], string[2]); - else - key = string[0]; - key = simplify_key(key, &modifiers); - 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; - } + write_port(gui.vdcmp, VimMsg::Key, &km, sizeof(km)); - if (modifiers) - { - *dest++ = CSI; - *dest++ = KS_MODIFIER; - *dest++ = modifiers; - km.length = 3; - } - } - memcpy((char *)dest, string, len); - km.length += len; - km.csi_escape = false; - } - - write_port(gui.vdcmp, VimMsg::Key, &km, sizeof(km)); - - /* - * blank out the pointer if necessary - */ - if (p_mh && !gui.pointer_hidden) - { - guiBlankMouse(true); - gui.pointer_hidden = TRUE; - } + /* + * blank out the pointer if necessary + */ + if (p_mh && !gui.pointer_hidden) + { + guiBlankMouse(true); + gui.pointer_hidden = TRUE; + } } void VimTextAreaView::guiSendMouseEvent( - int button, - int x, - int y, - int repeated_click, - int_u modifiers) + int button, + int x, + int y, + int repeated_click, + int_u modifiers) { - VimMouseMsg mm; + VimMouseMsg mm; - mm.button = button; - mm.x = x; - mm.y = y; - mm.repeated_click = repeated_click; - mm.modifiers = modifiers; + mm.button = button; + mm.x = x; + mm.y = y; + mm.repeated_click = repeated_click; + mm.modifiers = modifiers; - write_port(gui.vdcmp, VimMsg::Mouse, &mm, sizeof(mm)); - // calls gui_send_mouse_event() + write_port(gui.vdcmp, VimMsg::Mouse, &mm, sizeof(mm)); + // calls gui_send_mouse_event() - /* - * if our pointer is currently hidden, then we should show it. - */ - if (gui.pointer_hidden) - { - guiBlankMouse(false); - gui.pointer_hidden = FALSE; - } + /* + * if our pointer is currently hidden, then we should show it. + */ + if (gui.pointer_hidden) + { + guiBlankMouse(false); + gui.pointer_hidden = FALSE; + } } void VimTextAreaView::guiMouseMoved( - int x, - int y) + int x, + int y) { - VimMouseMovedMsg mm; + VimMouseMovedMsg mm; - mm.x = x; - mm.y = y; + mm.x = x; + mm.y = y; - write_port(gui.vdcmp, VimMsg::MouseMoved, &mm, sizeof(mm)); + write_port(gui.vdcmp, VimMsg::MouseMoved, &mm, sizeof(mm)); - if (gui.pointer_hidden) - { - guiBlankMouse(false); - gui.pointer_hidden = FALSE; - } + if (gui.pointer_hidden) + { + guiBlankMouse(false); + gui.pointer_hidden = FALSE; + } } - void + void VimTextAreaView::guiBlankMouse(bool should_hide) { - if (should_hide) { - // gui.vimApp->HideCursor(); - gui.vimApp->ObscureCursor(); - /* - * ObscureCursor() would even be easier, but then - * Vim's idea of mouse visibility does not necessarily - * correspond to reality. - */ - } else { - // gui.vimApp->ShowCursor(); - } + if (should_hide) { + // gui.vimApp->HideCursor(); + gui.vimApp->ObscureCursor(); + /* + * ObscureCursor() would even be easier, but then + * Vim's idea of mouse visibility does not necessarily + * correspond to reality. + */ + } else { + // gui.vimApp->ShowCursor(); + } } - int_u + int_u VimTextAreaView::mouseModifiersToVim(int32 beModifiers) { - int_u vim_modifiers = 0x0; + int_u vim_modifiers = 0x0; - if (beModifiers & B_SHIFT_KEY) - vim_modifiers |= MOUSE_SHIFT; - if (beModifiers & B_CONTROL_KEY) - vim_modifiers |= MOUSE_CTRL; - if (beModifiers & B_OPTION_KEY) // Alt or Meta key - vim_modifiers |= MOUSE_ALT; + if (beModifiers & B_SHIFT_KEY) + vim_modifiers |= MOUSE_SHIFT; + if (beModifiers & B_CONTROL_KEY) + vim_modifiers |= MOUSE_CTRL; + if (beModifiers & B_OPTION_KEY) // Alt or Meta key + vim_modifiers |= MOUSE_ALT; - return vim_modifiers; + return vim_modifiers; } - void + void VimTextAreaView::MouseDown(BPoint point) { - BMessage *m = Window()->CurrentMessage(); - assert(m); + BMessage *m = Window()->CurrentMessage(); + assert(m); - int32 buttons = 0; - m->FindInt32("buttons", &buttons); + int32 buttons = 0; + m->FindInt32("buttons", &buttons); - int vimButton; + int vimButton; - if (buttons & B_PRIMARY_MOUSE_BUTTON) - vimButton = MOUSE_LEFT; - else if (buttons & B_SECONDARY_MOUSE_BUTTON) - vimButton = MOUSE_RIGHT; - else if (buttons & B_TERTIARY_MOUSE_BUTTON) - vimButton = MOUSE_MIDDLE; - else - return; // Unknown button + if (buttons & B_PRIMARY_MOUSE_BUTTON) + vimButton = MOUSE_LEFT; + else if (buttons & B_SECONDARY_MOUSE_BUTTON) + vimButton = MOUSE_RIGHT; + else if (buttons & B_TERTIARY_MOUSE_BUTTON) + vimButton = MOUSE_MIDDLE; + else + return; // Unknown button - vimMouseButton = 1; // don't care which one + vimMouseButton = 1; // don't care which one - // Handle multiple clicks - int32 clicks = 0; - m->FindInt32("clicks", &clicks); + // Handle multiple clicks + int32 clicks = 0; + m->FindInt32("clicks", &clicks); - int32 modifiers = 0; - m->FindInt32("modifiers", &modifiers); + int32 modifiers = 0; + m->FindInt32("modifiers", &modifiers); - vimMouseModifiers = mouseModifiersToVim(modifiers); + vimMouseModifiers = mouseModifiersToVim(modifiers); - guiSendMouseEvent(vimButton, point.x, point.y, - clicks > 1 /* = repeated_click*/, vimMouseModifiers); + guiSendMouseEvent(vimButton, point.x, point.y, + clicks > 1 /* = repeated_click*/, vimMouseModifiers); } - void + void VimTextAreaView::MouseUp(BPoint point) { - vimMouseButton = 0; + vimMouseButton = 0; - BMessage *m = Window()->CurrentMessage(); - assert(m); - // m->PrintToStream(); + BMessage *m = Window()->CurrentMessage(); + assert(m); + // m->PrintToStream(); - int32 modifiers = 0; - m->FindInt32("modifiers", &modifiers); + int32 modifiers = 0; + m->FindInt32("modifiers", &modifiers); - vimMouseModifiers = mouseModifiersToVim(modifiers); + vimMouseModifiers = mouseModifiersToVim(modifiers); - guiSendMouseEvent(MOUSE_RELEASE, point.x, point.y, - 0 /* = repeated_click*/, vimMouseModifiers); + guiSendMouseEvent(MOUSE_RELEASE, point.x, point.y, + 0 /* = repeated_click*/, vimMouseModifiers); - Inherited::MouseUp(point); + Inherited::MouseUp(point); } - void + void VimTextAreaView::MouseMoved(BPoint point, uint32 transit, const BMessage *message) { - /* - * if our pointer is currently hidden, then we should show it. - */ - if (gui.pointer_hidden) - { - guiBlankMouse(false); - gui.pointer_hidden = FALSE; - } + /* + * if our pointer is currently hidden, then we should show it. + */ + if (gui.pointer_hidden) + { + guiBlankMouse(false); + gui.pointer_hidden = FALSE; + } - if (!vimMouseButton) { // could also check m->"buttons" - guiMouseMoved(point.x, point.y); - return; - } + if (!vimMouseButton) { // could also check m->"buttons" + guiMouseMoved(point.x, point.y); + return; + } - atomic_add(&mouseDragEventCount, 1); + atomic_add(&mouseDragEventCount, 1); - // Don't care much about "transit" - guiSendMouseEvent(MOUSE_DRAG, point.x, point.y, 0, vimMouseModifiers); + // Don't care much about "transit" + guiSendMouseEvent(MOUSE_DRAG, point.x, point.y, 0, vimMouseModifiers); } - void + void VimTextAreaView::MessageReceived(BMessage *m) { - switch (m->what) { - case 'menu': - { - VimMenuMsg mm; - mm.guiMenu = NULL; // in case no pointer in msg - m->FindPointer("VimMenu", (void **)&mm.guiMenu); - write_port(gui.vdcmp, VimMsg::Menu, &mm, sizeof(mm)); - } - break; - case B_MOUSE_WHEEL_CHANGED: - { - VimScrollBar* scb = curwin->w_scrollbars[1].id; - float small=0, big=0, dy=0; - m->FindFloat("be:wheel_delta_y", &dy); - scb->GetSteps(&small, &big); - scb->SetValue(scb->Value()+small*dy*3); - scb->ValueChanged(scb->Value()); + switch (m->what) { + case 'menu': + { + VimMenuMsg mm; + mm.guiMenu = NULL; // in case no pointer in msg + m->FindPointer("VimMenu", (void **)&mm.guiMenu); + write_port(gui.vdcmp, VimMsg::Menu, &mm, sizeof(mm)); + } + break; + case B_MOUSE_WHEEL_CHANGED: + { + VimScrollBar* scb = curwin->w_scrollbars[1].id; + float small=0, big=0, dy=0; + m->FindFloat("be:wheel_delta_y", &dy); + scb->GetSteps(&small, &big); + scb->SetValue(scb->Value()+small*dy*3); + scb->ValueChanged(scb->Value()); #if 0 - scb = curwin->w_scrollbars[0].id; - scb->GetSteps(&small, &big); - scb->SetValue(scb->Value()+small*dy); - scb->ValueChanged(scb->Value()); + scb = curwin->w_scrollbars[0].id; + scb->GetSteps(&small, &big); + scb->SetValue(scb->Value()+small*dy); + scb->ValueChanged(scb->Value()); #endif - } - break; + } + break; #ifdef FEAT_MBYTE_IME - case B_INPUT_METHOD_EVENT: + case B_INPUT_METHOD_EVENT: + { + int32 opcode; + m->FindInt32("be:opcode", &opcode); + switch(opcode) + { + case B_INPUT_METHOD_STARTED: + if (!IMData.messenger) delete IMData.messenger; + IMData.messenger = new BMessenger(); + m->FindMessenger("be:reply_to", IMData.messenger); + break; + case B_INPUT_METHOD_CHANGED: { - int32 opcode; - m->FindInt32("be:opcode", &opcode); - switch(opcode) + BString str; + bool confirmed; + if (IMData.message) *(IMData.message) = *m; + else IMData.message = new BMessage(*m); + DrawIMString(); + m->FindBool("be:confirmed", &confirmed); + if (confirmed) + { + m->FindString("be:string", &str); + char_u *chars = (char_u*)str.String(); + struct VimKeyMsg km; + km.csi_escape = true; + int clen; + int i = 0; + while (i < str.Length()) { - case B_INPUT_METHOD_STARTED: - if(!IMData.messenger) delete IMData.messenger; - IMData.messenger = new BMessenger(); - m->FindMessenger("be:reply_to", IMData.messenger); - break; - case B_INPUT_METHOD_CHANGED: - { - BString str; - bool confirmed; - if(IMData.message) *(IMData.message) = *m; - else IMData.message = new BMessage(*m); - DrawIMString(); - m->FindBool("be:confirmed", &confirmed); - if (confirmed) - { - m->FindString("be:string", &str); - char_u *chars = (char_u*)str.String(); - struct VimKeyMsg km; - km.csi_escape = true; - int clen; - int i = 0; - while (i < str.Length()) - { - clen = utf_ptr2len(chars+i); - memcpy(km.chars, chars+i, clen); - km.length = clen; - write_port(gui.vdcmp, VimMsg::Key, &km, sizeof(km)); - i += clen; - } - } - } - break; - case B_INPUT_METHOD_LOCATION_REQUEST: - { - BMessage msg(B_INPUT_METHOD_EVENT); - msg.AddInt32("be:opcode", B_INPUT_METHOD_LOCATION_REQUEST); - msg.AddPoint("be:location_reply", IMData.location); - msg.AddFloat("be:height_reply", FILL_Y(1)); - IMData.messenger->SendMessage(&msg); - } - break; - case B_INPUT_METHOD_STOPPED: - delete IMData.messenger; - delete IMData.message; - IMData.messenger = NULL; - IMData.message = NULL; - break; + clen = utf_ptr2len(chars+i); + memcpy(km.chars, chars+i, clen); + km.length = clen; + write_port(gui.vdcmp, VimMsg::Key, &km, sizeof(km)); + i += clen; } - } - // TODO: sz: break here??? -#endif - default: - if (m->WasDropped()) { - BWindow *w = Window(); - w->DetachCurrentMessage(); - w->Minimize(false); - VimApp::SendRefs(m, (modifiers() & B_SHIFT_KEY) != 0); - } else { - Inherited::MessageReceived(m); + } } break; - } + case B_INPUT_METHOD_LOCATION_REQUEST: + { + BMessage msg(B_INPUT_METHOD_EVENT); + msg.AddInt32("be:opcode", B_INPUT_METHOD_LOCATION_REQUEST); + msg.AddPoint("be:location_reply", IMData.location); + msg.AddFloat("be:height_reply", FILL_Y(1)); + IMData.messenger->SendMessage(&msg); + } + break; + case B_INPUT_METHOD_STOPPED: + delete IMData.messenger; + delete IMData.message; + IMData.messenger = NULL; + IMData.message = NULL; + break; + } + } + // TODO: sz: break here??? +#endif + default: + if (m->WasDropped()) { + BWindow *w = Window(); + w->DetachCurrentMessage(); + w->Minimize(false); + VimApp::SendRefs(m, (modifiers() & B_SHIFT_KEY) != 0); + } else { + Inherited::MessageReceived(m); + } + break; + } } - int + int VimTextAreaView::mchInitFont(char_u *name) { - VimFont *newFont = (VimFont *)gui_mch_get_font(name, 1); - if(newFont != NOFONT) { - gui.norm_font = (GuiFont)newFont; - gui_mch_set_font((GuiFont)newFont); - if (name && STRCMP(name, "*") != 0) - hl_set_font_name(name); + VimFont *newFont = (VimFont *)gui_mch_get_font(name, 1); + if (newFont != NOFONT) { + gui.norm_font = (GuiFont)newFont; + gui_mch_set_font((GuiFont)newFont); + if (name && STRCMP(name, "*") != 0) + hl_set_font_name(name); - SetDrawingMode(B_OP_COPY); + SetDrawingMode(B_OP_COPY); - /* - * 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. - */ - return OK; - } - return FAIL; + /* + * 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. + */ + return OK; + } + return FAIL; } - void + void VimTextAreaView::mchDrawString(int row, int col, char_u *s, int len, int flags) { - /* - * First we must erase the area, because DrawString won't do - * that for us. XXX Most of the time this is a waste of effort - * since the bachground has been erased already... DRAW_TRANSP - * should be set when appropriate!!! - * (Rectangles include the bottom and right edge) - */ - if (!(flags & DRAW_TRANSP)) { - int cells; - cells = 0; - for(int i=0; iGetFont(&font); - if(!font.IsFixed()) - { - char* p = (char*)s; - int32 clen, lastpos = 0; - BPoint where; - int cells; - while((p - (char*)s) < len) { - clen = utf_ptr2len((u_char*)p); - where.Set(TEXT_X(col+lastpos), TEXT_Y(row)); - DrawString(p, clen, where); - if (flags & DRAW_BOLD) { - where.x += 1.0; - SetDrawingMode(B_OP_BLEND); - DrawString(p, clen, where); - SetDrawingMode(B_OP_COPY); - } - cells = utf_ptr2cells((char_u *)p); - if(cells<4) lastpos += cells; - else lastpos++; - p += clen; - } + BRect r(FILL_X(col), FILL_Y(row), + FILL_X(col + cells) - PEN_WIDTH, FILL_Y(row + 1) - PEN_WIDTH); + FillRect(r, B_SOLID_LOW); + } + + BFont font; + this->GetFont(&font); + if (!font.IsFixed()) + { + char* p = (char*)s; + int32 clen, lastpos = 0; + BPoint where; + int cells; + while ((p - (char*)s) < len) { + clen = utf_ptr2len((u_char*)p); + where.Set(TEXT_X(col+lastpos), TEXT_Y(row)); + DrawString(p, clen, where); + if (flags & DRAW_BOLD) { + where.x += 1.0; + SetDrawingMode(B_OP_BLEND); + DrawString(p, clen, where); + SetDrawingMode(B_OP_COPY); + } + cells = utf_ptr2cells((char_u *)p); + if (cells<4) lastpos += cells; + else lastpos++; + p += clen; } - else - { - BPoint where(TEXT_X(col), TEXT_Y(row)); - DrawString((char*)s, len, where); - if (flags & DRAW_BOLD) { - where.x += 1.0; - SetDrawingMode(B_OP_BLEND); - DrawString((char*)s, len, where); - SetDrawingMode(B_OP_COPY); - } + } + else + { + BPoint where(TEXT_X(col), TEXT_Y(row)); + DrawString((char*)s, len, where); + if (flags & DRAW_BOLD) { + where.x += 1.0; + SetDrawingMode(B_OP_BLEND); + DrawString((char*)s, len, where); + SetDrawingMode(B_OP_COPY); + } + } + + if (flags & DRAW_UNDERL) { + int cells; + cells = 0; + for (int i=0; iLock()) { - // Clear one column more for when bold has spilled over - CopyBits(source, dest); - gui_clear_block(gui.scroll_region_bot - num_lines + 1, - gui.scroll_region_left, - gui.scroll_region_bot, gui.scroll_region_right); + if (gui.vimWindow->Lock()) { + // Clear one column more for when bold has spilled over + CopyBits(source, dest); + gui_clear_block(gui.scroll_region_bot - num_lines + 1, + gui.scroll_region_left, + gui.scroll_region_bot, gui.scroll_region_right); - gui.vimWindow->Unlock(); - /* - * The Draw() callback will be called now if some of the source - * bits were not in the visible region. - */ - } - // gui_x11_check_copy_area(); - // } + gui.vimWindow->Unlock(); + /* + * The Draw() callback will be called now if some of the source + * bits were not in the visible region. + */ + } + // gui_x11_check_copy_area(); + // } } /* * mchInsertLines() Lock()s the window by itself. */ - void + void VimTextAreaView::mchInsertLines(int row, int num_lines) { - BRect source, dest; + BRect source, dest; - // XXX Attempt at a hack: - gui.vimWindow->UpdateIfNeeded(); - source.left = FILL_X(gui.scroll_region_left); - source.top = FILL_Y(row); - source.right = FILL_X(gui.scroll_region_right + 1) - PEN_WIDTH; - source.bottom = FILL_Y(gui.scroll_region_bot - num_lines + 1) - PEN_WIDTH; + // XXX Attempt at a hack: + gui.vimWindow->UpdateIfNeeded(); + source.left = FILL_X(gui.scroll_region_left); + source.top = FILL_Y(row); + source.right = FILL_X(gui.scroll_region_right + 1) - PEN_WIDTH; + source.bottom = FILL_Y(gui.scroll_region_bot - num_lines + 1) - PEN_WIDTH; - dest.left = FILL_X(gui.scroll_region_left); - dest.top = FILL_Y(row + num_lines); - dest.right = FILL_X(gui.scroll_region_right + 1) - PEN_WIDTH; - dest.bottom = FILL_Y(gui.scroll_region_bot + 1) - PEN_WIDTH; + dest.left = FILL_X(gui.scroll_region_left); + dest.top = FILL_Y(row + num_lines); + dest.right = FILL_X(gui.scroll_region_right + 1) - PEN_WIDTH; + dest.bottom = FILL_Y(gui.scroll_region_bot + 1) - PEN_WIDTH; - if (gui.vimWindow->Lock()) { - // Clear one column more for when bold has spilled over - CopyBits(source, dest); - gui_clear_block(row, gui.scroll_region_left, - row + num_lines - 1, gui.scroll_region_right); + if (gui.vimWindow->Lock()) { + // Clear one column more for when bold has spilled over + CopyBits(source, dest); + gui_clear_block(row, gui.scroll_region_left, + row + num_lines - 1, gui.scroll_region_right); - gui.vimWindow->Unlock(); - /* - * The Draw() callback will be called now if some of the source - * bits were not in the visible region. - * However, if we scroll too fast it can't keep up and the - * update region gets messed up. This seems to be because copying - * un-Draw()n bits does not generate Draw() calls for the copy... - * I moved the hack to before the CopyBits() to reduce the - * amount of additional waiting needed. - */ + gui.vimWindow->Unlock(); + /* + * The Draw() callback will be called now if some of the source + * bits were not in the visible region. + * However, if we scroll too fast it can't keep up and the + * update region gets messed up. This seems to be because copying + * un-Draw()n bits does not generate Draw() calls for the copy... + * I moved the hack to before the CopyBits() to reduce the + * amount of additional waiting needed. + */ - // gui_x11_check_copy_area(); + // gui_x11_check_copy_area(); - } + } } #ifdef FEAT_MBYTE_IME @@ -1855,67 +1856,67 @@ VimTextAreaView::mchInsertLines(int row, int num_lines) */ void VimTextAreaView::DrawIMString(void) { - static const rgb_color r_highlight = {255, 152, 152, 255}, - b_highlight = {152, 203, 255, 255}; - BString str; - const char* s; - int len; - BMessage* msg = IMData.message; - if (!msg) - return; - gui_redraw_block(IMData.row, 0, - IMData.row + IMData.count, W_WIDTH(curwin), GUI_MON_NOCLEAR); - bool confirmed = false; - msg->FindBool("be:confirmed", &confirmed); - if (confirmed) - return; - rgb_color hcolor = HighColor(), lcolor = LowColor(); - msg->FindString("be:string", &str); - s = str.String(); - len = str.Length(); - SetHighColor(0, 0, 0); - IMData.row = gui.row; - IMData.col = gui.col; - int32 sel_start = 0, sel_end = 0; - msg->FindInt32("be:selection", 0, &sel_start); - msg->FindInt32("be:selection", 1, &sel_end); - int clen, cn; - BPoint pos(IMData.col, 0); - BRect r; - BPoint where; - IMData.location = ConvertToScreen( - BPoint(FILL_X(pos.x), FILL_Y(IMData.row + pos.y))); - for (int i=0; iFindBool("be:confirmed", &confirmed); + if (confirmed) + return; + rgb_color hcolor = HighColor(), lcolor = LowColor(); + msg->FindString("be:string", &str); + s = str.String(); + len = str.Length(); + SetHighColor(0, 0, 0); + IMData.row = gui.row; + IMData.col = gui.col; + int32 sel_start = 0, sel_end = 0; + msg->FindInt32("be:selection", 0, &sel_start); + msg->FindInt32("be:selection", 1, &sel_end); + int clen, cn; + BPoint pos(IMData.col, 0); + BRect r; + BPoint where; + IMData.location = ConvertToScreen( + BPoint(FILL_X(pos.x), FILL_Y(IMData.row + pos.y))); + for (int i=0; i W_WIDTH(curwin)) { - cn = utf_ptr2cells((char_u *)(s+i)); - clen = utf_ptr2len((char_u *)(s+i)); - if (pos.x + cn > W_WIDTH(curwin)) - { - pos.y++; - pos.x = 0; - } - if (sel_start<=i && i= 0.0 && newValue == ignoreValue) { - ignoreValue = -1; - return; - } + if (ignoreValue >= 0.0 && newValue == ignoreValue) { ignoreValue = -1; - /* - * We want to throttle the amount of scroll messages generated. - * Normally I presume you won't get a new message before we've - * handled the previous one, but because we're passing them on this - * happens very quickly. So instead we keep a counter of how many - * scroll events there are (or will be) in the VDCMP, and the - * throttling happens at the receiving end. - */ - atomic_add(&scrollEventCount, 1); + return; + } + ignoreValue = -1; + /* + * We want to throttle the amount of scroll messages generated. + * Normally I presume you won't get a new message before we've + * handled the previous one, but because we're passing them on this + * happens very quickly. So instead we keep a counter of how many + * scroll events there are (or will be) in the VDCMP, and the + * throttling happens at the receiving end. + */ + atomic_add(&scrollEventCount, 1); - struct VimScrollBarMsg sm; + struct VimScrollBarMsg sm; - sm.sb = this; - sm.value = (long) newValue; - sm.stillDragging = TRUE; + sm.sb = this; + sm.value = (long) newValue; + sm.stillDragging = TRUE; - write_port(gui.vdcmp, VimMsg::ScrollBar, &sm, sizeof(sm)); + write_port(gui.vdcmp, VimMsg::ScrollBar, &sm, sizeof(sm)); - // calls gui_drag_scrollbar(sb, newValue, TRUE); + // calls gui_drag_scrollbar(sb, newValue, TRUE); } /* @@ -1980,733 +1981,733 @@ VimScrollBar::ValueChanged(float newValue) * is outside... This has some funny effects... XXX * So we do special processing when the window de/activates. */ - void + void VimScrollBar::MouseUp(BPoint where) { - // BMessage *m = Window()->CurrentMessage(); - // m->PrintToStream(); + // BMessage *m = Window()->CurrentMessage(); + // m->PrintToStream(); - atomic_add(&scrollEventCount, 1); + atomic_add(&scrollEventCount, 1); - struct VimScrollBarMsg sm; + struct VimScrollBarMsg sm; - sm.sb = this; - sm.value = (long) Value(); - sm.stillDragging = FALSE; + sm.sb = this; + sm.value = (long) Value(); + sm.stillDragging = FALSE; - write_port(gui.vdcmp, VimMsg::ScrollBar, &sm, sizeof(sm)); + write_port(gui.vdcmp, VimMsg::ScrollBar, &sm, sizeof(sm)); - // calls gui_drag_scrollbar(sb, newValue, FALSE); + // calls gui_drag_scrollbar(sb, newValue, FALSE); - Inherited::MouseUp(where); + Inherited::MouseUp(where); } - void + void VimScrollBar::SetValue(float newValue) { - if (newValue == Value()) - return; + if (newValue == Value()) + return; - ignoreValue = newValue; - Inherited::SetValue(newValue); + ignoreValue = newValue; + Inherited::SetValue(newValue); } // ---------------- VimFont ---------------- VimFont::VimFont(): BFont() { - init(); + init(); } VimFont::VimFont(const VimFont *rhs): BFont(rhs) { - init(); + init(); } VimFont::VimFont(const BFont *rhs): BFont(rhs) { - init(); + init(); } VimFont::VimFont(const VimFont &rhs): BFont(rhs) { - init(); + init(); } VimFont::~VimFont() { } - void + void VimFont::init() { - next = NULL; - refcount = 1; - name = NULL; + next = NULL; + refcount = 1; + name = NULL; } // ---------------- VimDialog ---------------- #if defined(FEAT_GUI_DIALOG) -const unsigned int kVimDialogButtonMsg = 'VMDB'; -const unsigned int kVimDialogIconStripeWidth = 30; -const unsigned int kVimDialogButtonsSpacingX = 9; -const unsigned int kVimDialogButtonsSpacingY = 4; -const unsigned int kVimDialogSpacingX = 6; -const unsigned int kVimDialogSpacingY = 10; -const unsigned int kVimDialogMinimalWidth = 310; -const unsigned int kVimDialogMinimalHeight = 75; -const BRect kDefaultRect = +const unsigned int kVimDialogButtonMsg = 'VMDB'; +const unsigned int kVimDialogIconStripeWidth = 30; +const unsigned int kVimDialogButtonsSpacingX = 9; +const unsigned int kVimDialogButtonsSpacingY = 4; +const unsigned int kVimDialogSpacingX = 6; +const unsigned int kVimDialogSpacingY = 10; +const unsigned int kVimDialogMinimalWidth = 310; +const unsigned int kVimDialogMinimalHeight = 75; +const BRect kDefaultRect = BRect(0, 0, kVimDialogMinimalWidth, kVimDialogMinimalHeight); VimDialog::VimDialog(int type, const char *title, const char *message, - const char *buttons, int dfltbutton, const char *textfield, int ex_cmd) + const char *buttons, int dfltbutton, const char *textfield, int ex_cmd) : BWindow(kDefaultRect, title, B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL, - B_NOT_CLOSABLE | B_NOT_RESIZABLE | - B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE | B_ASYNCHRONOUS_CONTROLS) - , fDialogSem(-1) - , fDialogValue(dfltbutton) - , fMessageView(NULL) - , fInputControl(NULL) - , fInputValue(textfield) + B_NOT_CLOSABLE | B_NOT_RESIZABLE | + B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE | B_ASYNCHRONOUS_CONTROLS) + , fDialogSem(-1) + , fDialogValue(dfltbutton) + , fMessageView(NULL) + , fInputControl(NULL) + , fInputValue(textfield) { - // master view - VimDialog::View* view = new VimDialog::View(Bounds()); - if(view == NULL) - return; + // master view + VimDialog::View* view = new VimDialog::View(Bounds()); + if (view == NULL) + return; - if(title == NULL) - SetTitle("Vim " VIM_VERSION_MEDIUM); + if (title == NULL) + SetTitle("Vim " VIM_VERSION_MEDIUM); - AddChild(view); + AddChild(view); - // icon - view->InitIcon(type); + // icon + view->InitIcon(type); - // buttons - int32 which = 1; - float maxButtonWidth = 0; - float maxButtonHeight = 0; - float buttonsWidth = 0; - float buttonsHeight = 0; - BString strButtons(buttons); - strButtons.RemoveAll("&"); - do { - int32 end = strButtons.FindFirst('\n'); - if(end != B_ERROR) - strButtons.SetByteAt(end, '\0'); + // buttons + int32 which = 1; + float maxButtonWidth = 0; + float maxButtonHeight = 0; + float buttonsWidth = 0; + float buttonsHeight = 0; + BString strButtons(buttons); + strButtons.RemoveAll("&"); + do { + int32 end = strButtons.FindFirst('\n'); + if (end != B_ERROR) + strButtons.SetByteAt(end, '\0'); - BButton *button = _CreateButton(which++, strButtons.String()); - view->AddChild(button); - fButtonsList.AddItem(button); + BButton *button = _CreateButton(which++, strButtons.String()); + view->AddChild(button); + fButtonsList.AddItem(button); - maxButtonWidth = max_c(maxButtonWidth, button->Bounds().Width()); - maxButtonHeight = max_c(maxButtonHeight, button->Bounds().Height()); - buttonsWidth += button->Bounds().Width(); - buttonsHeight += button->Bounds().Height(); + maxButtonWidth = max_c(maxButtonWidth, button->Bounds().Width()); + maxButtonHeight = max_c(maxButtonHeight, button->Bounds().Height()); + buttonsWidth += button->Bounds().Width(); + buttonsHeight += button->Bounds().Height(); - if(end == B_ERROR) - break; + if (end == B_ERROR) + break; - strButtons.Remove(0, end + 1); - } while(true); + strButtons.Remove(0, end + 1); + } while (true); - int32 buttonsCount = fButtonsList.CountItems(); - buttonsWidth += kVimDialogButtonsSpacingX * (buttonsCount - 1); - buttonsHeight += kVimDialogButtonsSpacingY * (buttonsCount - 1); - float dialogWidth = buttonsWidth + kVimDialogIconStripeWidth + - kVimDialogSpacingX * 2; - float dialogHeight = maxButtonHeight + kVimDialogSpacingY * 3; + int32 buttonsCount = fButtonsList.CountItems(); + buttonsWidth += kVimDialogButtonsSpacingX * (buttonsCount - 1); + buttonsHeight += kVimDialogButtonsSpacingY * (buttonsCount - 1); + float dialogWidth = buttonsWidth + kVimDialogIconStripeWidth + + kVimDialogSpacingX * 2; + float dialogHeight = maxButtonHeight + kVimDialogSpacingY * 3; - // Check 'v' flag in 'guioptions': vertical button placement. - bool vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL) || - dialogWidth >= gui.vimWindow->Bounds().Width(); - if(vertical) { - dialogWidth -= buttonsWidth; - dialogWidth += maxButtonWidth; - dialogHeight -= maxButtonHeight; - dialogHeight += buttonsHeight; - } - - dialogWidth = max_c(dialogWidth, kVimDialogMinimalWidth); - - // message view - BRect rect(0, 0, dialogWidth, 0); - rect.left += kVimDialogIconStripeWidth + 16 + kVimDialogSpacingX; - rect.top += kVimDialogSpacingY; - rect.right -= kVimDialogSpacingX; - rect.bottom = rect.top; - fMessageView = new BTextView(rect, "_tv_", rect.OffsetByCopy(B_ORIGIN), - B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW); - - fMessageView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); - rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR); - fMessageView->SetFontAndColor(be_plain_font, B_FONT_ALL, &textColor); - fMessageView->SetText(message); - fMessageView->MakeEditable(false); - fMessageView->MakeSelectable(false); - fMessageView->SetWordWrap(true); - AddChild(fMessageView); - - float messageHeight = fMessageView->TextHeight(0, fMessageView->CountLines()); - fMessageView->ResizeBy(0, messageHeight); - fMessageView->SetTextRect(BRect(0, 0, rect.Width(), messageHeight)); - - dialogHeight += messageHeight; - - // input view - if(fInputValue != NULL) { - rect.top = - rect.bottom += messageHeight + kVimDialogSpacingY; - fInputControl = new BTextControl(rect, "_iv_", NULL, fInputValue, NULL, - B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE | B_PULSE_NEEDED); - fInputControl->TextView()->SetText(fInputValue); - fInputControl->TextView()->SetWordWrap(false); - AddChild(fInputControl); - - float width = 0.f, height = 0.f; - fInputControl->GetPreferredSize(&width, &height); - fInputControl->MakeFocus(true); - - dialogHeight += height + kVimDialogSpacingY * 1.5; - } - - dialogHeight = max_c(dialogHeight, kVimDialogMinimalHeight); - - ResizeTo(dialogWidth, dialogHeight); - MoveTo((gui.vimWindow->Bounds().Width() - dialogWidth) / 2, - (gui.vimWindow->Bounds().Height() - dialogHeight) / 2); - - // adjust layout of buttons - float buttonWidth = max_c(maxButtonWidth, rect.Width() * 0.66); - BPoint origin(dialogWidth, dialogHeight); - origin.x -= kVimDialogSpacingX + (vertical ? buttonWidth : buttonsWidth); - origin.y -= kVimDialogSpacingY + (vertical ? buttonsHeight : maxButtonHeight); - - for(int32 i = 0 ; i < buttonsCount; i++) { - BButton *button = (BButton*)fButtonsList.ItemAt(i); - button->MoveTo(origin); - if(vertical) { - origin.y += button->Frame().Height() + kVimDialogButtonsSpacingY; - button->ResizeTo(buttonWidth, button->Frame().Height()); - } else - origin.x += button->Frame().Width() + kVimDialogButtonsSpacingX; - - if(dfltbutton == i + 1) { - button->MakeDefault(true); - button->MakeFocus(fInputControl == NULL); - } + // Check 'v' flag in 'guioptions': vertical button placement. + bool vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL) || + dialogWidth >= gui.vimWindow->Bounds().Width(); + if (vertical) { + dialogWidth -= buttonsWidth; + dialogWidth += maxButtonWidth; + dialogHeight -= maxButtonHeight; + dialogHeight += buttonsHeight; + } + + dialogWidth = max_c(dialogWidth, kVimDialogMinimalWidth); + + // message view + BRect rect(0, 0, dialogWidth, 0); + rect.left += kVimDialogIconStripeWidth + 16 + kVimDialogSpacingX; + rect.top += kVimDialogSpacingY; + rect.right -= kVimDialogSpacingX; + rect.bottom = rect.top; + fMessageView = new BTextView(rect, "_tv_", rect.OffsetByCopy(B_ORIGIN), + B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW); + + fMessageView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR); + fMessageView->SetFontAndColor(be_plain_font, B_FONT_ALL, &textColor); + fMessageView->SetText(message); + fMessageView->MakeEditable(false); + fMessageView->MakeSelectable(false); + fMessageView->SetWordWrap(true); + AddChild(fMessageView); + + float messageHeight = fMessageView->TextHeight(0, fMessageView->CountLines()); + fMessageView->ResizeBy(0, messageHeight); + fMessageView->SetTextRect(BRect(0, 0, rect.Width(), messageHeight)); + + dialogHeight += messageHeight; + + // input view + if (fInputValue != NULL) { + rect.top = + rect.bottom += messageHeight + kVimDialogSpacingY; + fInputControl = new BTextControl(rect, "_iv_", NULL, fInputValue, NULL, + B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE | B_PULSE_NEEDED); + fInputControl->TextView()->SetText(fInputValue); + fInputControl->TextView()->SetWordWrap(false); + AddChild(fInputControl); + + float width = 0.f, height = 0.f; + fInputControl->GetPreferredSize(&width, &height); + fInputControl->MakeFocus(true); + + dialogHeight += height + kVimDialogSpacingY * 1.5; + } + + dialogHeight = max_c(dialogHeight, kVimDialogMinimalHeight); + + ResizeTo(dialogWidth, dialogHeight); + MoveTo((gui.vimWindow->Bounds().Width() - dialogWidth) / 2, + (gui.vimWindow->Bounds().Height() - dialogHeight) / 2); + + // adjust layout of buttons + float buttonWidth = max_c(maxButtonWidth, rect.Width() * 0.66); + BPoint origin(dialogWidth, dialogHeight); + origin.x -= kVimDialogSpacingX + (vertical ? buttonWidth : buttonsWidth); + origin.y -= kVimDialogSpacingY + (vertical ? buttonsHeight : maxButtonHeight); + + for (int32 i = 0 ; i < buttonsCount; i++) { + BButton *button = (BButton*)fButtonsList.ItemAt(i); + button->MoveTo(origin); + if (vertical) { + origin.y += button->Frame().Height() + kVimDialogButtonsSpacingY; + button->ResizeTo(buttonWidth, button->Frame().Height()); + } else + origin.x += button->Frame().Width() + kVimDialogButtonsSpacingX; + + if (dfltbutton == i + 1) { + button->MakeDefault(true); + button->MakeFocus(fInputControl == NULL); } + } } VimDialog::~VimDialog() { - if(fDialogSem > B_OK) - delete_sem(fDialogSem); + if (fDialogSem > B_OK) + delete_sem(fDialogSem); } - int + int VimDialog::Go() { - fDialogSem = create_sem(0, "VimDialogSem"); - if(fDialogSem < B_OK) { - Quit(); - return fDialogValue; - } + fDialogSem = create_sem(0, "VimDialogSem"); + if (fDialogSem < B_OK) { + Quit(); + return fDialogValue; + } - Show(); + Show(); - while(acquire_sem(fDialogSem) == B_INTERRUPTED); + while (acquire_sem(fDialogSem) == B_INTERRUPTED); - int retValue = fDialogValue; - if(fInputValue != NULL) - vim_strncpy((char_u*)fInputValue, (char_u*)fInputControl->Text(), IOSIZE - 1); + int retValue = fDialogValue; + if (fInputValue != NULL) + vim_strncpy((char_u*)fInputValue, (char_u*)fInputControl->Text(), IOSIZE - 1); - if(Lock()) - Quit(); + if (Lock()) + Quit(); - return retValue; + return retValue; } void VimDialog::MessageReceived(BMessage *msg) { - int32 which = 0; - if(msg->what != kVimDialogButtonMsg || - msg->FindInt32("which", &which) != B_OK) - return BWindow::MessageReceived(msg); + int32 which = 0; + if (msg->what != kVimDialogButtonMsg || + msg->FindInt32("which", &which) != B_OK) + return BWindow::MessageReceived(msg); - fDialogValue = which; - delete_sem(fDialogSem); - fDialogSem = -1; + fDialogValue = which; + delete_sem(fDialogSem); + fDialogSem = -1; } BButton* VimDialog::_CreateButton(int32 which, const char* label) { - BMessage *message = new BMessage(kVimDialogButtonMsg); - message->AddInt32("which", which); + BMessage *message = new BMessage(kVimDialogButtonMsg); + message->AddInt32("which", which); - BRect rect(0, 0, 0, 0); - BString name; - name << "_b" << which << "_"; + BRect rect(0, 0, 0, 0); + BString name; + name << "_b" << which << "_"; - BButton* button = new BButton(rect, name.String(), label, message, - B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); + BButton* button = new BButton(rect, name.String(), label, message, + B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); - float width = 0.f, height = 0.f; - button->GetPreferredSize(&width, &height); - button->ResizeTo(width, height); + float width = 0.f, height = 0.f; + button->GetPreferredSize(&width, &height); + button->ResizeTo(width, height); - return button; + return button; } VimDialog::View::View(BRect frame) - : BView(frame, "VimDialogView", B_FOLLOW_ALL_SIDES, B_WILL_DRAW), - fIconBitmap(NULL) + : BView(frame, "VimDialogView", B_FOLLOW_ALL_SIDES, B_WILL_DRAW), + fIconBitmap(NULL) { - SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); } VimDialog::View::~View() { - delete fIconBitmap; + delete fIconBitmap; } void VimDialog::View::Draw(BRect updateRect) { - BRect stripeRect = Bounds(); - stripeRect.right = kVimDialogIconStripeWidth; - SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT)); - FillRect(stripeRect); + BRect stripeRect = Bounds(); + stripeRect.right = kVimDialogIconStripeWidth; + SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT)); + FillRect(stripeRect); - if(fIconBitmap == NULL) - return; + if (fIconBitmap == NULL) + return; - SetDrawingMode(B_OP_ALPHA); - SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); - DrawBitmapAsync(fIconBitmap, BPoint(18, 6)); + SetDrawingMode(B_OP_ALPHA); + SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); + DrawBitmapAsync(fIconBitmap, BPoint(18, 6)); } void VimDialog::View::InitIcon(int32 type) { - if(type == VIM_GENERIC) - return; + if (type == VIM_GENERIC) + return; - BPath path; - status_t status = find_directory(B_BEOS_SERVERS_DIRECTORY, &path); - if(status != B_OK) { - fprintf(stderr, "Cannot retrieve app info:%s\n", strerror(status)); - return; - } + BPath path; + status_t status = find_directory(B_BEOS_SERVERS_DIRECTORY, &path); + if (status != B_OK) { + fprintf(stderr, "Cannot retrieve app info:%s\n", strerror(status)); + return; + } - path.Append("app_server"); + path.Append("app_server"); - BFile file(path.Path(), O_RDONLY); - if(file.InitCheck() != B_OK) { - fprintf(stderr, "App file assignment failed:%s\n", - strerror(file.InitCheck())); - return; - } + BFile file(path.Path(), O_RDONLY); + if (file.InitCheck() != B_OK) { + fprintf(stderr, "App file assignment failed:%s\n", + strerror(file.InitCheck())); + return; + } - BResources resources(&file); - if(resources.InitCheck() != B_OK) { - fprintf(stderr, "App server resources assignment failed:%s\n", - strerror(resources.InitCheck())); - return; - } + BResources resources(&file); + if (resources.InitCheck() != B_OK) { + fprintf(stderr, "App server resources assignment failed:%s\n", + strerror(resources.InitCheck())); + return; + } - const char *name = ""; - switch(type) { - case VIM_ERROR: name = "stop"; break; - case VIM_WARNING: name = "warn"; break; - case VIM_INFO: name = "info"; break; - case VIM_QUESTION: name = "idea"; break; - default: return; - } + const char *name = ""; + switch(type) { + case VIM_ERROR: name = "stop"; break; + case VIM_WARNING: name = "warn"; break; + case VIM_INFO: name = "info"; break; + case VIM_QUESTION: name = "idea"; break; + default: return; + } - int32 iconSize = 32; - fIconBitmap = new BBitmap(BRect(0, 0, iconSize - 1, iconSize - 1), 0, B_RGBA32); - if(fIconBitmap == NULL || fIconBitmap->InitCheck() != B_OK) { - fprintf(stderr, "Icon bitmap allocation failed:%s\n", - (fIconBitmap == NULL) ? "null" : strerror(fIconBitmap->InitCheck())); - return; - } + int32 iconSize = 32; + fIconBitmap = new BBitmap(BRect(0, 0, iconSize - 1, iconSize - 1), 0, B_RGBA32); + if (fIconBitmap == NULL || fIconBitmap->InitCheck() != B_OK) { + fprintf(stderr, "Icon bitmap allocation failed:%s\n", + (fIconBitmap == NULL) ? "null" : strerror(fIconBitmap->InitCheck())); + return; + } - size_t size = 0; - const uint8* iconData = NULL; - // try vector icon first? - iconData = (const uint8*)resources.LoadResource(B_VECTOR_ICON_TYPE, name, &size); - if(iconData != NULL && BIconUtils::GetVectorIcon(iconData, size, fIconBitmap) == B_OK) - return; + size_t size = 0; + const uint8* iconData = NULL; + // try vector icon first? + iconData = (const uint8*)resources.LoadResource(B_VECTOR_ICON_TYPE, name, &size); + if (iconData != NULL && BIconUtils::GetVectorIcon(iconData, size, fIconBitmap) == B_OK) + return; - // try bitmap icon now - iconData = (const uint8*)resources.LoadResource(B_LARGE_ICON_TYPE, name, &size); - if(iconData == NULL) { - fprintf(stderr, "Bitmap icon resource not found\n"); - delete fIconBitmap; - fIconBitmap = NULL; - return; - } + // try bitmap icon now + iconData = (const uint8*)resources.LoadResource(B_LARGE_ICON_TYPE, name, &size); + if (iconData == NULL) { + fprintf(stderr, "Bitmap icon resource not found\n"); + delete fIconBitmap; + fIconBitmap = NULL; + return; + } - if(fIconBitmap->ColorSpace() != B_CMAP8) - BIconUtils::ConvertFromCMAP8(iconData, iconSize, iconSize, iconSize, fIconBitmap); + if (fIconBitmap->ColorSpace() != B_CMAP8) + BIconUtils::ConvertFromCMAP8(iconData, iconSize, iconSize, iconSize, fIconBitmap); } -const unsigned int kVimDialogOKButtonMsg = 'FDOK'; -const unsigned int kVimDialogCancelButtonMsg = 'FDCN'; -const unsigned int kVimDialogSizeInputMsg = 'SICH'; -const unsigned int kVimDialogFamilySelectMsg = 'MSFM'; -const unsigned int kVimDialogStyleSelectMsg = 'MSST'; -const unsigned int kVimDialogSizeSelectMsg = 'MSSZ'; +const unsigned int kVimDialogOKButtonMsg = 'FDOK'; +const unsigned int kVimDialogCancelButtonMsg = 'FDCN'; +const unsigned int kVimDialogSizeInputMsg = 'SICH'; +const unsigned int kVimDialogFamilySelectMsg = 'MSFM'; +const unsigned int kVimDialogStyleSelectMsg = 'MSST'; +const unsigned int kVimDialogSizeSelectMsg = 'MSSZ'; VimSelectFontDialog::VimSelectFontDialog(font_family* family, font_style* style, float* size) : BWindow(kDefaultRect, "Font Selection", B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL, - B_NOT_CLOSABLE | B_NOT_RESIZABLE | - B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE | B_ASYNCHRONOUS_CONTROLS) - , fStatus(B_NO_INIT) - , fDialogSem(-1) - , fDialogValue(false) - , fFamily(family) - , fStyle(style) - , fSize(size) - , fFontSize(*size) - , fPreview(0) - , fFamiliesList(0) - , fStylesList(0) - , fSizesList(0) - , fSizesInput(0) + B_NOT_CLOSABLE | B_NOT_RESIZABLE | + B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE | B_ASYNCHRONOUS_CONTROLS) + , fStatus(B_NO_INIT) + , fDialogSem(-1) + , fDialogValue(false) + , fFamily(family) + , fStyle(style) + , fSize(size) + , fFontSize(*size) + , fPreview(0) + , fFamiliesList(0) + , fStylesList(0) + , fSizesList(0) + , fSizesInput(0) { - strncpy(fFontFamily, *family, B_FONT_FAMILY_LENGTH); - strncpy(fFontStyle, *style, B_FONT_STYLE_LENGTH); + strncpy(fFontFamily, *family, B_FONT_FAMILY_LENGTH); + strncpy(fFontStyle, *style, B_FONT_STYLE_LENGTH); - // "client" area view - BBox *clientBox = new BBox(Bounds(), B_EMPTY_STRING, B_FOLLOW_ALL_SIDES, - B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP | B_PULSE_NEEDED, - B_PLAIN_BORDER); - AddChild(clientBox); + // "client" area view + BBox *clientBox = new BBox(Bounds(), B_EMPTY_STRING, B_FOLLOW_ALL_SIDES, + B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP | B_PULSE_NEEDED, + B_PLAIN_BORDER); + AddChild(clientBox); - // client view - BRect RC = clientBox->Bounds(); - RC.InsetBy(kVimDialogSpacingX, kVimDialogSpacingY); - BRect rc(RC.LeftTop(), RC.LeftTop()); + // client view + BRect RC = clientBox->Bounds(); + RC.InsetBy(kVimDialogSpacingX, kVimDialogSpacingY); + BRect rc(RC.LeftTop(), RC.LeftTop()); - // at first create all controls - fPreview = new BStringView(rc, "preview", "DejaVu Sans Mono"); - clientBox->AddChild(fPreview); + // at first create all controls + fPreview = new BStringView(rc, "preview", "DejaVu Sans Mono"); + clientBox->AddChild(fPreview); - BBox* boxDivider = new BBox(rc, B_EMPTY_STRING, - B_FOLLOW_NONE, B_WILL_DRAW, B_FANCY_BORDER); - clientBox->AddChild(boxDivider); + BBox* boxDivider = new BBox(rc, B_EMPTY_STRING, + B_FOLLOW_NONE, B_WILL_DRAW, B_FANCY_BORDER); + clientBox->AddChild(boxDivider); - BStringView *labelFamily = new BStringView(rc, "labelFamily", "Family:"); - clientBox->AddChild(labelFamily); - labelFamily->ResizeToPreferred(); + BStringView *labelFamily = new BStringView(rc, "labelFamily", "Family:"); + clientBox->AddChild(labelFamily); + labelFamily->ResizeToPreferred(); - BStringView *labelStyle = new BStringView(rc, "labelStyle", "Style:"); - clientBox->AddChild(labelStyle); - labelStyle->ResizeToPreferred(); + BStringView *labelStyle = new BStringView(rc, "labelStyle", "Style:"); + clientBox->AddChild(labelStyle); + labelStyle->ResizeToPreferred(); - BStringView *labelSize = new BStringView(rc, "labelSize", "Size:"); - clientBox->AddChild(labelSize); - labelSize->ResizeToPreferred(); + BStringView *labelSize = new BStringView(rc, "labelSize", "Size:"); + clientBox->AddChild(labelSize); + labelSize->ResizeToPreferred(); - fFamiliesList = new BListView(rc, "listFamily", - B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL_SIDES); - BScrollView *scrollFamilies = new BScrollView("scrollFamily", - fFamiliesList, B_FOLLOW_LEFT_RIGHT, 0, false, true); - clientBox->AddChild(scrollFamilies); + fFamiliesList = new BListView(rc, "listFamily", + B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL_SIDES); + BScrollView *scrollFamilies = new BScrollView("scrollFamily", + fFamiliesList, B_FOLLOW_LEFT_RIGHT, 0, false, true); + clientBox->AddChild(scrollFamilies); - fStylesList= new BListView(rc, "listStyles", - B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL_SIDES); - BScrollView *scrollStyles = new BScrollView("scrollStyle", - fStylesList, B_FOLLOW_LEFT_RIGHT, 0, false, true); - clientBox->AddChild(scrollStyles); + fStylesList= new BListView(rc, "listStyles", + B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL_SIDES); + BScrollView *scrollStyles = new BScrollView("scrollStyle", + fStylesList, B_FOLLOW_LEFT_RIGHT, 0, false, true); + clientBox->AddChild(scrollStyles); - fSizesInput = new BTextControl(rc, "inputSize", NULL, "???", - new BMessage(kVimDialogSizeInputMsg)); - clientBox->AddChild(fSizesInput); - fSizesInput->ResizeToPreferred(); + fSizesInput = new BTextControl(rc, "inputSize", NULL, "???", + new BMessage(kVimDialogSizeInputMsg)); + clientBox->AddChild(fSizesInput); + fSizesInput->ResizeToPreferred(); - fSizesList = new BListView(rc, "listSizes", - B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL_SIDES); - BScrollView *scrollSizes = new BScrollView("scrollSize", - fSizesList, B_FOLLOW_LEFT_RIGHT, 0, false, true); - clientBox->AddChild(scrollSizes); + fSizesList = new BListView(rc, "listSizes", + B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL_SIDES); + BScrollView *scrollSizes = new BScrollView("scrollSize", + fSizesList, B_FOLLOW_LEFT_RIGHT, 0, false, true); + clientBox->AddChild(scrollSizes); - BButton *buttonOK = new BButton(rc, "buttonOK", "OK", - new BMessage(kVimDialogOKButtonMsg)); - clientBox->AddChild(buttonOK); - buttonOK->ResizeToPreferred(); + BButton *buttonOK = new BButton(rc, "buttonOK", "OK", + new BMessage(kVimDialogOKButtonMsg)); + clientBox->AddChild(buttonOK); + buttonOK->ResizeToPreferred(); - BButton *buttonCancel = new BButton(rc, "buttonCancel", "Cancel", - new BMessage(kVimDialogCancelButtonMsg)); - clientBox->AddChild(buttonCancel); - buttonCancel->ResizeToPreferred(); + BButton *buttonCancel = new BButton(rc, "buttonCancel", "Cancel", + new BMessage(kVimDialogCancelButtonMsg)); + clientBox->AddChild(buttonCancel); + buttonCancel->ResizeToPreferred(); - // layout controls - float lineHeight = labelFamily->Bounds().Height(); - float previewHeight = lineHeight * 3; - float offsetYLabels = previewHeight + kVimDialogSpacingY; - float offsetYLists = offsetYLabels + lineHeight + kVimDialogSpacingY / 2; - float offsetYSizes = offsetYLists + fSizesInput->Bounds().Height() + kVimDialogSpacingY / 2; - float listsHeight = lineHeight * 9; - float offsetYButtons = offsetYLists + listsHeight + kVimDialogSpacingY; - float maxControlsHeight = offsetYButtons + buttonOK->Bounds().Height(); - float familiesWidth = labelFamily->Bounds().Width() * 5; - float offsetXStyles = familiesWidth + kVimDialogSpacingX; - float stylesWidth = labelStyle->Bounds().Width() * 4; - float offsetXSizes = offsetXStyles + stylesWidth + kVimDialogSpacingX; - float sizesWidth = labelSize->Bounds().Width() * 2; - float maxControlsWidth = offsetXSizes + sizesWidth; + // layout controls + float lineHeight = labelFamily->Bounds().Height(); + float previewHeight = lineHeight * 3; + float offsetYLabels = previewHeight + kVimDialogSpacingY; + float offsetYLists = offsetYLabels + lineHeight + kVimDialogSpacingY / 2; + float offsetYSizes = offsetYLists + fSizesInput->Bounds().Height() + kVimDialogSpacingY / 2; + float listsHeight = lineHeight * 9; + float offsetYButtons = offsetYLists + listsHeight + kVimDialogSpacingY; + float maxControlsHeight = offsetYButtons + buttonOK->Bounds().Height(); + float familiesWidth = labelFamily->Bounds().Width() * 5; + float offsetXStyles = familiesWidth + kVimDialogSpacingX; + float stylesWidth = labelStyle->Bounds().Width() * 4; + float offsetXSizes = offsetXStyles + stylesWidth + kVimDialogSpacingX; + float sizesWidth = labelSize->Bounds().Width() * 2; + float maxControlsWidth = offsetXSizes + sizesWidth; - ResizeTo(maxControlsWidth + kVimDialogSpacingX * 2, - maxControlsHeight + kVimDialogSpacingY * 2); + ResizeTo(maxControlsWidth + kVimDialogSpacingX * 2, + maxControlsHeight + kVimDialogSpacingY * 2); - BRect rcVim = gui.vimWindow->Frame(); - MoveTo(rcVim.left + (rcVim.Width() - Frame().Width()) / 2, - rcVim.top + (rcVim.Height() - Frame().Height()) / 2); + BRect rcVim = gui.vimWindow->Frame(); + MoveTo(rcVim.left + (rcVim.Width() - Frame().Width()) / 2, + rcVim.top + (rcVim.Height() - Frame().Height()) / 2); - fPreview->ResizeTo(maxControlsWidth, previewHeight); - fPreview->SetAlignment(B_ALIGN_CENTER); + fPreview->ResizeTo(maxControlsWidth, previewHeight); + fPreview->SetAlignment(B_ALIGN_CENTER); - boxDivider->MoveBy(0.f, previewHeight + kVimDialogSpacingY / 2); - boxDivider->ResizeTo(maxControlsWidth, 1.f); + boxDivider->MoveBy(0.f, previewHeight + kVimDialogSpacingY / 2); + boxDivider->ResizeTo(maxControlsWidth, 1.f); - labelFamily->MoveBy(0.f, offsetYLabels); - labelStyle->MoveBy(offsetXStyles, offsetYLabels); - labelSize->MoveBy(offsetXSizes, offsetYLabels); + labelFamily->MoveBy(0.f, offsetYLabels); + labelStyle->MoveBy(offsetXStyles, offsetYLabels); + labelSize->MoveBy(offsetXSizes, offsetYLabels); - // text control alignment issues - float insetX = fSizesInput->TextView()->Bounds().Width() - fSizesInput->Bounds().Width(); - float insetY = fSizesInput->TextView()->Bounds().Width() - fSizesInput->Bounds().Width(); + // text control alignment issues + float insetX = fSizesInput->TextView()->Bounds().Width() - fSizesInput->Bounds().Width(); + float insetY = fSizesInput->TextView()->Bounds().Width() - fSizesInput->Bounds().Width(); - scrollFamilies->MoveBy(0.f, offsetYLists); - scrollStyles->MoveBy(offsetXStyles, offsetYLists); - fSizesInput->MoveBy(offsetXSizes + insetX / 2, offsetYLists + insetY / 2); - scrollSizes->MoveBy(offsetXSizes, offsetYSizes); + scrollFamilies->MoveBy(0.f, offsetYLists); + scrollStyles->MoveBy(offsetXStyles, offsetYLists); + fSizesInput->MoveBy(offsetXSizes + insetX / 2, offsetYLists + insetY / 2); + scrollSizes->MoveBy(offsetXSizes, offsetYSizes); - fSizesInput->SetAlignment(B_ALIGN_CENTER, B_ALIGN_CENTER); + fSizesInput->SetAlignment(B_ALIGN_CENTER, B_ALIGN_CENTER); - scrollFamilies->ResizeTo(familiesWidth, listsHeight); - scrollStyles->ResizeTo(stylesWidth, listsHeight); - fSizesInput->ResizeTo(sizesWidth, fSizesInput->Bounds().Height()); - scrollSizes->ResizeTo(sizesWidth, - listsHeight - (offsetYSizes - offsetYLists)); + scrollFamilies->ResizeTo(familiesWidth, listsHeight); + scrollStyles->ResizeTo(stylesWidth, listsHeight); + fSizesInput->ResizeTo(sizesWidth, fSizesInput->Bounds().Height()); + scrollSizes->ResizeTo(sizesWidth, + listsHeight - (offsetYSizes - offsetYLists)); - buttonOK->MoveBy(maxControlsWidth - buttonOK->Bounds().Width(), offsetYButtons); - buttonCancel->MoveBy(maxControlsWidth - buttonOK->Bounds().Width() - - buttonCancel->Bounds().Width() - kVimDialogSpacingX, offsetYButtons); + buttonOK->MoveBy(maxControlsWidth - buttonOK->Bounds().Width(), offsetYButtons); + buttonCancel->MoveBy(maxControlsWidth - buttonOK->Bounds().Width() + - buttonCancel->Bounds().Width() - kVimDialogSpacingX, offsetYButtons); - // fill lists - int selIndex = -1; - int count = count_font_families(); - for (int i = 0; i < count; i++) { - font_family family; - if (get_font_family(i, &family ) == B_OK) { - fFamiliesList->AddItem(new BStringItem((const char*)family)); - if (strncmp(family, fFontFamily, B_FONT_FAMILY_LENGTH) == 0) - selIndex = i; - } + // fill lists + int selIndex = -1; + int count = count_font_families(); + for (int i = 0; i < count; i++) { + font_family family; + if (get_font_family(i, &family ) == B_OK) { + fFamiliesList->AddItem(new BStringItem((const char*)family)); + if (strncmp(family, fFontFamily, B_FONT_FAMILY_LENGTH) == 0) + selIndex = i; } + } - if (selIndex >= 0) { - fFamiliesList->Select(selIndex); - fFamiliesList->ScrollToSelection(); - } + if (selIndex >= 0) { + fFamiliesList->Select(selIndex); + fFamiliesList->ScrollToSelection(); + } - _UpdateFontStyles(); + _UpdateFontStyles(); - selIndex = -1; - for (int size = 8, index = 0; size <= 18; size++, index++) { - BString str; - str << size; - fSizesList->AddItem(new BStringItem(str)); - if (size == fFontSize) - selIndex = index; + selIndex = -1; + for (int size = 8, index = 0; size <= 18; size++, index++) { + BString str; + str << size; + fSizesList->AddItem(new BStringItem(str)); + if (size == fFontSize) + selIndex = index; - } + } - if (selIndex >= 0) { - fSizesList->Select(selIndex); - fSizesList->ScrollToSelection(); - } + if (selIndex >= 0) { + fSizesList->Select(selIndex); + fSizesList->ScrollToSelection(); + } - fFamiliesList->SetSelectionMessage(new BMessage(kVimDialogFamilySelectMsg)); - fStylesList->SetSelectionMessage(new BMessage(kVimDialogStyleSelectMsg)); - fSizesList->SetSelectionMessage(new BMessage(kVimDialogSizeSelectMsg)); - fSizesInput->SetModificationMessage(new BMessage(kVimDialogSizeInputMsg)); + fFamiliesList->SetSelectionMessage(new BMessage(kVimDialogFamilySelectMsg)); + fStylesList->SetSelectionMessage(new BMessage(kVimDialogStyleSelectMsg)); + fSizesList->SetSelectionMessage(new BMessage(kVimDialogSizeSelectMsg)); + fSizesInput->SetModificationMessage(new BMessage(kVimDialogSizeInputMsg)); - _UpdateSizeInputPreview(); - _UpdateFontPreview(); + _UpdateSizeInputPreview(); + _UpdateFontPreview(); - fStatus = B_OK; + fStatus = B_OK; } VimSelectFontDialog::~VimSelectFontDialog() { - _CleanList(fFamiliesList); - _CleanList(fStylesList); - _CleanList(fSizesList); + _CleanList(fFamiliesList); + _CleanList(fStylesList); + _CleanList(fSizesList); - if (fDialogSem > B_OK) - delete_sem(fDialogSem); + if (fDialogSem > B_OK) + delete_sem(fDialogSem); } - void + void VimSelectFontDialog::_CleanList(BListView* list) { - while(0 < list->CountItems()) - delete (dynamic_cast(list->RemoveItem((int32)0))); + while (0 < list->CountItems()) + delete (dynamic_cast(list->RemoveItem((int32)0))); } - bool + bool VimSelectFontDialog::Go() { - if (fStatus != B_OK) { - Quit(); - return NOFONT; - } + if (fStatus != B_OK) { + Quit(); + return NOFONT; + } - fDialogSem = create_sem(0, "VimFontSelectDialogSem"); - if(fDialogSem < B_OK) { - Quit(); - return fDialogValue; - } + fDialogSem = create_sem(0, "VimFontSelectDialogSem"); + if (fDialogSem < B_OK) { + Quit(); + return fDialogValue; + } - Show(); + Show(); - while(acquire_sem(fDialogSem) == B_INTERRUPTED); + while (acquire_sem(fDialogSem) == B_INTERRUPTED); - bool retValue = fDialogValue; + bool retValue = fDialogValue; - if(Lock()) - Quit(); + if (Lock()) + Quit(); - return retValue; + return retValue; } void VimSelectFontDialog::_UpdateFontStyles() { - _CleanList(fStylesList); + _CleanList(fStylesList); - int32 selIndex = -1; - int32 count = count_font_styles(fFontFamily); - for (int32 i = 0; i < count; i++) { - font_style style; - uint32 flags = 0; - if (get_font_style(fFontFamily, i, &style, &flags) == B_OK) { - fStylesList->AddItem(new BStringItem((const char*)style)); - if (strncmp(style, fFontStyle, B_FONT_STYLE_LENGTH) == 0) - selIndex = i; - } + int32 selIndex = -1; + int32 count = count_font_styles(fFontFamily); + for (int32 i = 0; i < count; i++) { + font_style style; + uint32 flags = 0; + if (get_font_style(fFontFamily, i, &style, &flags) == B_OK) { + fStylesList->AddItem(new BStringItem((const char*)style)); + if (strncmp(style, fFontStyle, B_FONT_STYLE_LENGTH) == 0) + selIndex = i; } + } - if (selIndex >= 0) { - fStylesList->Select(selIndex); - fStylesList->ScrollToSelection(); - } else - fStylesList->Select(0); + if (selIndex >= 0) { + fStylesList->Select(selIndex); + fStylesList->ScrollToSelection(); + } else + fStylesList->Select(0); } void VimSelectFontDialog::_UpdateSizeInputPreview() { - char buf[10] = {0}; - vim_snprintf(buf, sizeof(buf), (char*)"%.0f", fFontSize); - fSizesInput->SetText(buf); + char buf[10] = {0}; + vim_snprintf(buf, sizeof(buf), (char*)"%.0f", fFontSize); + fSizesInput->SetText(buf); } void VimSelectFontDialog::_UpdateFontPreview() { - BFont font; - fPreview->GetFont(&font); - font.SetSize(fFontSize); - font.SetFamilyAndStyle(fFontFamily, fFontStyle); - fPreview->SetFont(&font, B_FONT_FAMILY_AND_STYLE | B_FONT_SIZE); + BFont font; + fPreview->GetFont(&font); + font.SetSize(fFontSize); + font.SetFamilyAndStyle(fFontFamily, fFontStyle); + fPreview->SetFont(&font, B_FONT_FAMILY_AND_STYLE | B_FONT_SIZE); - BString str; - str << fFontFamily << " " << fFontStyle << ", " << (int)fFontSize << " pt."; - fPreview->SetText(str); + BString str; + str << fFontFamily << " " << fFontStyle << ", " << (int)fFontSize << " pt."; + fPreview->SetText(str); } - bool + bool VimSelectFontDialog::_UpdateFromListItem(BListView* list, char* text, int textSize) { - int32 index = list->CurrentSelection(); - if (index < 0) - return false; - BStringItem* item = (BStringItem*)list->ItemAt(index); - if (item == NULL) - return false; - strncpy(text, item->Text(), textSize); - return true; + int32 index = list->CurrentSelection(); + if (index < 0) + return false; + BStringItem* item = (BStringItem*)list->ItemAt(index); + if (item == NULL) + return false; + strncpy(text, item->Text(), textSize); + return true; } void VimSelectFontDialog::MessageReceived(BMessage *msg) { - switch (msg->what) { - case kVimDialogOKButtonMsg: - strncpy(*fFamily, fFontFamily, B_FONT_FAMILY_LENGTH); - strncpy(*fStyle, fFontStyle, B_FONT_STYLE_LENGTH); - *fSize = fFontSize; - fDialogValue = true; - case kVimDialogCancelButtonMsg: - delete_sem(fDialogSem); - fDialogSem = -1; - return; - case B_KEY_UP: - { - int32 key = 0; - if (msg->FindInt32("raw_char", &key) == B_OK - && key == B_ESCAPE) { - delete_sem(fDialogSem); - fDialogSem = -1; - } - } - break; + switch (msg->what) { + case kVimDialogOKButtonMsg: + strncpy(*fFamily, fFontFamily, B_FONT_FAMILY_LENGTH); + strncpy(*fStyle, fFontStyle, B_FONT_STYLE_LENGTH); + *fSize = fFontSize; + fDialogValue = true; + case kVimDialogCancelButtonMsg: + delete_sem(fDialogSem); + fDialogSem = -1; + return; + case B_KEY_UP: + { + int32 key = 0; + if (msg->FindInt32("raw_char", &key) == B_OK + && key == B_ESCAPE) { + delete_sem(fDialogSem); + fDialogSem = -1; + } + } + break; - case kVimDialogFamilySelectMsg: - if (_UpdateFromListItem(fFamiliesList, - fFontFamily, B_FONT_FAMILY_LENGTH)) { - _UpdateFontStyles(); - _UpdateFontPreview(); - } - break; - case kVimDialogStyleSelectMsg: - if (_UpdateFromListItem(fStylesList, - fFontStyle, B_FONT_STYLE_LENGTH)) - _UpdateFontPreview(); - break; - case kVimDialogSizeSelectMsg: - { - char buf[10] = {0}; - if (_UpdateFromListItem(fSizesList, buf, sizeof(buf))) { - float size = atof(buf); - if (size > 0.f) { - fFontSize = size; - _UpdateSizeInputPreview(); - _UpdateFontPreview(); - } - } - } - break; - case kVimDialogSizeInputMsg: - { - float size = atof(fSizesInput->Text()); - if (size > 0.f) { - fFontSize = size; - _UpdateFontPreview(); - } - } - break; - default: - break; - } - return BWindow::MessageReceived(msg); + case kVimDialogFamilySelectMsg: + if (_UpdateFromListItem(fFamiliesList, + fFontFamily, B_FONT_FAMILY_LENGTH)) { + _UpdateFontStyles(); + _UpdateFontPreview(); + } + break; + case kVimDialogStyleSelectMsg: + if (_UpdateFromListItem(fStylesList, + fFontStyle, B_FONT_STYLE_LENGTH)) + _UpdateFontPreview(); + break; + case kVimDialogSizeSelectMsg: + { + char buf[10] = {0}; + if (_UpdateFromListItem(fSizesList, buf, sizeof(buf))) { + float size = atof(buf); + if (size > 0.f) { + fFontSize = size; + _UpdateSizeInputPreview(); + _UpdateFontPreview(); + } + } + } + break; + case kVimDialogSizeInputMsg: + { + float size = atof(fSizesInput->Text()); + if (size > 0.f) { + fFontSize = size; + _UpdateFontPreview(); + } + } + break; + default: + break; + } + return BWindow::MessageReceived(msg); } #endif // FEAT_GUI_DIALOG @@ -2717,328 +2718,330 @@ void VimSelectFontDialog::MessageReceived(BMessage *msg) static BMessage * MenuMessage(vimmenu_T *menu); VimToolbar::VimToolbar(BRect frame, const char *name) : - BBox(frame, name, B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_FRAME_EVENTS, B_PLAIN_BORDER) + BBox(frame, name, B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_FRAME_EVENTS, B_PLAIN_BORDER) { } VimToolbar::~VimToolbar() { - int32 count = fButtonsList.CountItems(); - for(int32 i = 0; i < count; i++) - delete (BPictureButton*)fButtonsList.ItemAt(i); - fButtonsList.MakeEmpty(); + int32 count = fButtonsList.CountItems(); + for (int32 i = 0; i < count; i++) + delete (BPictureButton*)fButtonsList.ItemAt(i); + fButtonsList.MakeEmpty(); - delete normalButtonsBitmap; - delete grayedButtonsBitmap; - normalButtonsBitmap = NULL; - grayedButtonsBitmap = NULL; + delete normalButtonsBitmap; + delete grayedButtonsBitmap; + normalButtonsBitmap = NULL; + grayedButtonsBitmap = NULL; } - void + void VimToolbar::AttachedToWindow() { - BBox::AttachedToWindow(); + BBox::AttachedToWindow(); - SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); } - float + float VimToolbar::ToolbarHeight() const { - float size = NULL == normalButtonsBitmap ? 18. : normalButtonsBitmap->Bounds().Height(); - return size + ToolbarMargin * 2 + ButtonMargin * 2 + 1; + float size = NULL == normalButtonsBitmap ? 18. : normalButtonsBitmap->Bounds().Height(); + return size + ToolbarMargin * 2 + ButtonMargin * 2 + 1; } - bool + bool VimToolbar::ModifyBitmapToGrayed(BBitmap *bitmap) { - float height = bitmap->Bounds().Height(); - float width = bitmap->Bounds().Width(); + float height = bitmap->Bounds().Height(); + float width = bitmap->Bounds().Width(); - rgb_color *bits = (rgb_color*)bitmap->Bits(); - int32 pixels = bitmap->BitsLength() / 4; - for(int32 i = 0; i < pixels; i++) { - bits[i].red = bits[i].green = - bits[i].blue = ((uint32)bits[i].red + bits[i].green + bits[i].blue) / 3; - bits[i].alpha /= 4; - } + rgb_color *bits = (rgb_color*)bitmap->Bits(); + int32 pixels = bitmap->BitsLength() / 4; + for (int32 i = 0; i < pixels; i++) { + bits[i].red = bits[i].green = + bits[i].blue = ((uint32)bits[i].red + bits[i].green + bits[i].blue) / 3; + bits[i].alpha /= 4; + } - return true; + return true; } - bool + bool VimToolbar::PrepareButtonBitmaps() { - // first try to load potentially customized $VIRUNTIME/bitmaps/builtin-tools.png - normalButtonsBitmap = LoadVimBitmap("builtin-tools.png"); - if(normalButtonsBitmap == NULL) - // customized not found? dig application resources for "builtin-tools" one - normalButtonsBitmap = BTranslationUtils::GetBitmap(B_PNG_FORMAT, "builtin-tools"); + // first try to load potentially customized $VIRUNTIME/bitmaps/builtin-tools.png + normalButtonsBitmap = LoadVimBitmap("builtin-tools.png"); + if (normalButtonsBitmap == NULL) + // customized not found? dig application resources for "builtin-tools" one + normalButtonsBitmap = BTranslationUtils::GetBitmap(B_PNG_FORMAT, "builtin-tools"); - if(normalButtonsBitmap == NULL) - return false; + if (normalButtonsBitmap == NULL) + return false; - BMessage archive; - normalButtonsBitmap->Archive(&archive); + BMessage archive; + normalButtonsBitmap->Archive(&archive); - grayedButtonsBitmap = new BBitmap(&archive); - if(grayedButtonsBitmap == NULL) - return false; + grayedButtonsBitmap = new BBitmap(&archive); + if (grayedButtonsBitmap == NULL) + return false; - // modify grayed bitmap - ModifyBitmapToGrayed(grayedButtonsBitmap); + // modify grayed bitmap + ModifyBitmapToGrayed(grayedButtonsBitmap); - return true; + return true; } BBitmap *VimToolbar::LoadVimBitmap(const char* fileName) { - BBitmap *bitmap = NULL; + BBitmap *bitmap = NULL; - int mustfree = 0; - char_u* runtimePath = vim_getenv((char_u*)"VIMRUNTIME", &mustfree); - if(runtimePath != NULL && fileName != NULL) { - BString strPath((char*)runtimePath); - strPath << "/bitmaps/" << fileName; - bitmap = BTranslationUtils::GetBitmap(strPath.String()); - } + int mustfree = 0; + char_u* runtimePath = vim_getenv((char_u*)"VIMRUNTIME", &mustfree); + if (runtimePath != NULL && fileName != NULL) { + BString strPath((char*)runtimePath); + strPath << "/bitmaps/" << fileName; + bitmap = BTranslationUtils::GetBitmap(strPath.String()); + } - if(mustfree) - vim_free(runtimePath); + if (mustfree) + vim_free(runtimePath); - return bitmap; + return bitmap; } - bool + bool VimToolbar::GetPictureFromBitmap(BPicture *pictureTo, int32 index, BBitmap *bitmapFrom, bool pressed) { - float size = bitmapFrom->Bounds().Height() + 1.; + float size = bitmapFrom->Bounds().Height() + 1.; - BView view(BRect(0, 0, size, size), "", 0, 0); + BView view(BRect(0, 0, size, size), "", 0, 0); - AddChild(&view); - view.BeginPicture(pictureTo); + AddChild(&view); + view.BeginPicture(pictureTo); - view.SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR)); - view.FillRect(view.Bounds()); - view.SetDrawingMode(B_OP_OVER); + view.SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + view.FillRect(view.Bounds()); + view.SetDrawingMode(B_OP_OVER); - BRect source(0, 0, size - 1, size - 1); - BRect destination(source); + BRect source(0, 0, size - 1, size - 1); + BRect destination(source); - source.OffsetBy(size * index, 0); - destination.OffsetBy(ButtonMargin, ButtonMargin); + source.OffsetBy(size * index, 0); + destination.OffsetBy(ButtonMargin, ButtonMargin); - view.DrawBitmap(bitmapFrom, source, destination); + view.DrawBitmap(bitmapFrom, source, destination); - if(pressed) { - rgb_color shineColor = ui_color(B_SHINE_COLOR); - rgb_color shadowColor = ui_color(B_SHADOW_COLOR); - size += ButtonMargin * 2 - 1; - view.BeginLineArray(4); - view.AddLine(BPoint(0, 0), BPoint(size, 0), shadowColor); - view.AddLine(BPoint(size, 0), BPoint(size, size), shineColor); - view.AddLine(BPoint(size, size), BPoint(0, size), shineColor); - view.AddLine(BPoint(0, size), BPoint(0, 0), shadowColor); - view.EndLineArray(); - } + if (pressed) { + rgb_color shineColor = ui_color(B_SHINE_COLOR); + rgb_color shadowColor = ui_color(B_SHADOW_COLOR); + size += ButtonMargin * 2 - 1; + view.BeginLineArray(4); + view.AddLine(BPoint(0, 0), BPoint(size, 0), shadowColor); + view.AddLine(BPoint(size, 0), BPoint(size, size), shineColor); + view.AddLine(BPoint(size, size), BPoint(0, size), shineColor); + view.AddLine(BPoint(0, size), BPoint(0, 0), shadowColor); + view.EndLineArray(); + } - view.EndPicture(); - RemoveChild(&view); + view.EndPicture(); + RemoveChild(&view); - return true; + return true; } - bool + bool VimToolbar::AddButton(int32 index, vimmenu_T *menu) { - BPictureButton *button = NULL; - if(!menu_is_separator(menu->name)) { - float size = normalButtonsBitmap ? - normalButtonsBitmap->Bounds().Height() + 1. + ButtonMargin * 2 : 18.; - BRect frame(0, 0, size, size); - BPicture pictureOn; - BPicture pictureOff; - BPicture pictureGray; + BPictureButton *button = NULL; + if (!menu_is_separator(menu->name)) { + float size = normalButtonsBitmap ? + normalButtonsBitmap->Bounds().Height() + 1. + ButtonMargin * 2 : 18.; + BRect frame(0, 0, size, size); + BPicture pictureOn; + BPicture pictureOff; + BPicture pictureGray; - if(menu->iconfile == NULL && menu->iconidx >= 0 && normalButtonsBitmap) { - GetPictureFromBitmap(&pictureOn, menu->iconidx, normalButtonsBitmap, true); - GetPictureFromBitmap(&pictureOff, menu->iconidx, normalButtonsBitmap, false); - GetPictureFromBitmap(&pictureGray, menu->iconidx, grayedButtonsBitmap, false); - } else { + if (menu->iconfile == NULL && menu->iconidx >= 0 && normalButtonsBitmap) { + GetPictureFromBitmap(&pictureOn, menu->iconidx, normalButtonsBitmap, true); + GetPictureFromBitmap(&pictureOff, menu->iconidx, normalButtonsBitmap, false); + GetPictureFromBitmap(&pictureGray, menu->iconidx, grayedButtonsBitmap, false); + } else { - char_u buffer[MAXPATHL] = {0}; - BBitmap *bitmap = NULL; + char_u buffer[MAXPATHL] = {0}; + BBitmap *bitmap = NULL; - if(menu->iconfile) { - gui_find_iconfile(menu->iconfile, buffer, (char*)"png"); - bitmap = BTranslationUtils::GetBitmap((char*)buffer); - } + if (menu->iconfile) { + gui_find_iconfile(menu->iconfile, buffer, (char*)"png"); + bitmap = BTranslationUtils::GetBitmap((char*)buffer); + } - if(bitmap == NULL && gui_find_bitmap(menu->name, buffer, (char*)"png") == OK) - bitmap = BTranslationUtils::GetBitmap((char*)buffer); + if (bitmap == NULL && gui_find_bitmap(menu->name, buffer, (char*)"png") == OK) + bitmap = BTranslationUtils::GetBitmap((char*)buffer); - if(bitmap == NULL) - bitmap = new BBitmap(BRect(0, 0, size, size), B_RGB32); + if (bitmap == NULL) + bitmap = new BBitmap(BRect(0, 0, size, size), B_RGB32); - GetPictureFromBitmap(&pictureOn, 0, bitmap, true); - GetPictureFromBitmap(&pictureOff, 0, bitmap, false); - ModifyBitmapToGrayed(bitmap); - GetPictureFromBitmap(&pictureGray, 0, bitmap, false); + GetPictureFromBitmap(&pictureOn, 0, bitmap, true); + GetPictureFromBitmap(&pictureOff, 0, bitmap, false); + ModifyBitmapToGrayed(bitmap); + GetPictureFromBitmap(&pictureGray, 0, bitmap, false); - delete bitmap; - } - - button = new BPictureButton(frame, (char*)menu->name, - &pictureOff, &pictureOn, MenuMessage(menu)); - - button->SetDisabledOn(&pictureGray); - button->SetDisabledOff(&pictureGray); - - button->SetTarget(gui.vimTextArea); - - AddChild(button); - - menu->button = button; + delete bitmap; } - bool result = fButtonsList.AddItem(button, index); - InvalidateLayout(); - return result; + button = new BPictureButton(frame, (char*)menu->name, + &pictureOff, &pictureOn, MenuMessage(menu)); + + button->SetDisabledOn(&pictureGray); + button->SetDisabledOff(&pictureGray); + + button->SetTarget(gui.vimTextArea); + + AddChild(button); + + menu->button = button; + } + + bool result = fButtonsList.AddItem(button, index); + InvalidateLayout(); + return result; } - bool + bool VimToolbar::RemoveButton(vimmenu_T *menu) { - if(menu->button) { - if(fButtonsList.RemoveItem(menu->button)) { - delete menu->button; - menu->button = NULL; - } + if (menu->button) { + if (fButtonsList.RemoveItem(menu->button)) { + delete menu->button; + menu->button = NULL; } + } + return true; } - bool + bool VimToolbar::GrayButton(vimmenu_T *menu, int grey) { - if(menu->button) { - int32 index = fButtonsList.IndexOf(menu->button); - if(index >= 0) - menu->button->SetEnabled(grey ? false : true); - } + if (menu->button) { + int32 index = fButtonsList.IndexOf(menu->button); + if (index >= 0) + menu->button->SetEnabled(grey ? false : true); + } + return true; } - void + void VimToolbar::InvalidateLayout() { - int32 offset = ToolbarMargin; - int32 count = fButtonsList.CountItems(); - for(int32 i = 0; i < count; i++) { - BPictureButton *button = (BPictureButton *)fButtonsList.ItemAt(i); - if(button) { - button->MoveTo(offset, ToolbarMargin); - offset += button->Bounds().Width() + ToolbarMargin; - } else - offset += ToolbarMargin * 3; - } + int32 offset = ToolbarMargin; + int32 count = fButtonsList.CountItems(); + for (int32 i = 0; i < count; i++) { + BPictureButton *button = (BPictureButton *)fButtonsList.ItemAt(i); + if (button) { + button->MoveTo(offset, ToolbarMargin); + offset += button->Bounds().Width() + ToolbarMargin; + } else + offset += ToolbarMargin * 3; + } } #endif /*FEAT_TOOLBAR*/ #if defined(FEAT_GUI_TABLINE) - float + float VimTabLine::TablineHeight() const { -// float size = NULL == normalButtonsBitmap ? 18. : normalButtonsBitmap->Bounds().Height(); -// return size + ToolbarMargin * 2 + ButtonMargin * 2 + 1; - return TabHeight(); // + ToolbarMargin; +// float size = NULL == normalButtonsBitmap ? 18. : normalButtonsBitmap->Bounds().Height(); +// return size + ToolbarMargin * 2 + ButtonMargin * 2 + 1; + return TabHeight(); // + ToolbarMargin; } void VimTabLine::MouseDown(BPoint point) { - if(!gui_mch_showing_tabline()) - return; + if (!gui_mch_showing_tabline()) + return; - BMessage *m = Window()->CurrentMessage(); - assert(m); + BMessage *m = Window()->CurrentMessage(); + assert(m); - int32 buttons = 0; - m->FindInt32("buttons", &buttons); + int32 buttons = 0; + m->FindInt32("buttons", &buttons); - int32 clicks = 0; - m->FindInt32("clicks", &clicks); + int32 clicks = 0; + m->FindInt32("clicks", &clicks); - int index = 0; // 0 means here - no tab found - for (int i = 0; i < CountTabs(); i++) { - if(TabFrame(i).Contains(point)) { - index = i + 1; // indexes are 1-based - break; - } + int index = 0; // 0 means here - no tab found + for (int i = 0; i < CountTabs(); i++) { + if (TabFrame(i).Contains(point)) { + index = i + 1; // indexes are 1-based + break; + } + } + + int event = -1; + + if ((buttons & B_PRIMARY_MOUSE_BUTTON) && clicks > 1) + // left button double click on - create new tab + event = TABLINE_MENU_NEW; + + else if (buttons & B_TERTIARY_MOUSE_BUTTON) + // middle button click - close the pointed tab + // or create new one in case empty space + event = index > 0 ? TABLINE_MENU_CLOSE : TABLINE_MENU_NEW; + + else if (buttons & B_SECONDARY_MOUSE_BUTTON) { + // right button click - show context menu + BPopUpMenu* popUpMenu = new BPopUpMenu("tabLineContextMenu", false, false); + popUpMenu->AddItem(new BMenuItem(_("Close tabi R"), new BMessage(TABLINE_MENU_CLOSE))); + popUpMenu->AddItem(new BMenuItem(_("New tab T"), new BMessage(TABLINE_MENU_NEW))); + popUpMenu->AddItem(new BMenuItem(_("Open tab..."), new BMessage(TABLINE_MENU_OPEN))); + + ConvertToScreen(&point); + BMenuItem* item = popUpMenu->Go(point); + if (item != NULL) { + event = item->Command(); } - int event = -1; + delete popUpMenu; - if ((buttons & B_PRIMARY_MOUSE_BUTTON) && clicks > 1) - // left button double click on - create new tab - event = TABLINE_MENU_NEW; + } else { + // default processing + BTabView::MouseDown(point); + return; + } - else if (buttons & B_TERTIARY_MOUSE_BUTTON) - // middle button click - close the pointed tab - // or create new one in case empty space - event = index > 0 ? TABLINE_MENU_CLOSE : TABLINE_MENU_NEW; + if (event < 0) + return; - else if (buttons & B_SECONDARY_MOUSE_BUTTON) { - // right button click - show context menu - BPopUpMenu* popUpMenu = new BPopUpMenu("tabLineContextMenu", false, false); - popUpMenu->AddItem(new BMenuItem(_("Close tabi R"), new BMessage(TABLINE_MENU_CLOSE))); - popUpMenu->AddItem(new BMenuItem(_("New tab T"), new BMessage(TABLINE_MENU_NEW))); - popUpMenu->AddItem(new BMenuItem(_("Open tab..."), new BMessage(TABLINE_MENU_OPEN))); - - ConvertToScreen(&point); - BMenuItem* item = popUpMenu->Go(point); - if (item != NULL) { - event = item->Command(); - } - - delete popUpMenu; - - } else { - // default processing - BTabView::MouseDown(point); - return; - } - - if (event < 0) - return; - - VimTablineMenuMsg tmm; - tmm.index = index; - tmm.event = event; - write_port(gui.vdcmp, VimMsg::TablineMenu, &tmm, sizeof(tmm)); + VimTablineMenuMsg tmm; + tmm.index = index; + tmm.event = event; + write_port(gui.vdcmp, VimMsg::TablineMenu, &tmm, sizeof(tmm)); } void VimTabLine::VimTab::Select(BView* owner) { - BTab::Select(owner); + BTab::Select(owner); - VimTabLine *tabLine = gui.vimForm->TabLine(); - if(tabLine != NULL) { + VimTabLine *tabLine = gui.vimForm->TabLine(); + if (tabLine != NULL) { - int32 i = 0; - for (; i < tabLine->CountTabs(); i++) - if(this == tabLine->TabAt(i)) - break; + int32 i = 0; + for (; i < tabLine->CountTabs(); i++) + if (this == tabLine->TabAt(i)) + break; -// printf("%d:%d:%s\n", i, tabLine->CountTabs(), tabLine->TabAt(i)->Label()); - if(i < tabLine->CountTabs()) { - VimTablineMsg tm; - tm.index = i + 1; - write_port(gui.vdcmp, VimMsg::Tabline, &tm, sizeof(tm)); - } +// printf("%d:%d:%s\n", i, tabLine->CountTabs(), tabLine->TabAt(i)->Label()); + if (i < tabLine->CountTabs()) { + VimTablineMsg tm; + tm.index = i + 1; + write_port(gui.vdcmp, VimMsg::Tabline, &tm, sizeof(tm)); } + } } #endif // defined(FEAT_GUI_TABLINE) @@ -3051,123 +3054,123 @@ key_map *keyMap; char *keyMapChars; int main_exitcode = 127; - status_t + status_t gui_haiku_process_event(bigtime_t timeout) { - struct VimMsg vm; - int32 what; - ssize_t size; + struct VimMsg vm; + int32 what; + ssize_t size; - size = read_port_etc(gui.vdcmp, &what, &vm, sizeof(vm), - B_TIMEOUT, timeout); + size = read_port_etc(gui.vdcmp, &what, &vm, sizeof(vm), + B_TIMEOUT, timeout); - if (size >= 0) { - switch (what) { - case VimMsg::Key: - { - char_u *string = vm.u.Key.chars; - int len = vm.u.Key.length; - if (len == 1 && string[0] == Ctrl_chr('C')) { - trash_input_buf(); - got_int = TRUE; - } + if (size >= 0) { + switch (what) { + case VimMsg::Key: + { + char_u *string = vm.u.Key.chars; + int len = vm.u.Key.length; + if (len == 1 && string[0] == Ctrl_chr('C')) { + trash_input_buf(); + got_int = TRUE; + } - if (vm.u.Key.csi_escape) + if (vm.u.Key.csi_escape) #ifndef FEAT_MBYTE_IME - { - int i; - char_u buf[2]; + { + int i; + char_u buf[2]; - for (i = 0; i < len; ++i) - { - add_to_input_buf(string + i, 1); - if (string[i] == CSI) - { - // Turn CSI into K_CSI. - buf[0] = KS_EXTRA; - buf[1] = (int)KE_CSI; - add_to_input_buf(buf, 2); - } - } - } + for (i = 0; i < len; ++i) + { + add_to_input_buf(string + i, 1); + if (string[i] == CSI) + { + // Turn CSI into K_CSI. + buf[0] = KS_EXTRA; + buf[1] = (int)KE_CSI; + add_to_input_buf(buf, 2); + } + } + } #else - add_to_input_buf_csi(string, len); + add_to_input_buf_csi(string, len); #endif - else - add_to_input_buf(string, len); - } - break; - case VimMsg::Resize: - gui_resize_shell(vm.u.NewSize.width, vm.u.NewSize.height); - break; - case VimMsg::ScrollBar: - { - /* - * If loads of scroll messages queue up, use only the last - * one. Always report when the scrollbar stops dragging. - * This is not perfect yet anyway: these events are queued - * yet again, this time in the keyboard input buffer. - */ - int32 oldCount = - atomic_add(&vm.u.Scroll.sb->scrollEventCount, -1); - if (oldCount <= 1 || !vm.u.Scroll.stillDragging) - gui_drag_scrollbar(vm.u.Scroll.sb->getGsb(), - vm.u.Scroll.value, vm.u.Scroll.stillDragging); - } - break; -#if defined(FEAT_MENU) - case VimMsg::Menu: - gui_menu_cb(vm.u.Menu.guiMenu); - break; -#endif - case VimMsg::Mouse: - { - int32 oldCount; - if (vm.u.Mouse.button == MOUSE_DRAG) - oldCount = - atomic_add(&gui.vimTextArea->mouseDragEventCount, -1); - else - oldCount = 0; - if (oldCount <= 1) - gui_send_mouse_event(vm.u.Mouse.button, vm.u.Mouse.x, - vm.u.Mouse.y, vm.u.Mouse.repeated_click, - vm.u.Mouse.modifiers); - } - break; - case VimMsg::MouseMoved: - { - gui_mouse_moved(vm.u.MouseMoved.x, vm.u.MouseMoved.y); - } - break; - case VimMsg::Focus: - gui.in_focus = vm.u.Focus.active; - // XXX Signal that scrollbar dragging has stopped? - // This is needed because we don't get a MouseUp if - // that happens while outside the window... :-( - if (gui.dragged_sb) { - gui.dragged_sb = SBAR_NONE; - } - // gui_update_cursor(TRUE, FALSE); - break; - case VimMsg::Refs: - ::RefsReceived(vm.u.Refs.message, vm.u.Refs.changedir); - break; - case VimMsg::Tabline: - send_tabline_event(vm.u.Tabline.index); - break; - case VimMsg::TablineMenu: - send_tabline_menu_event(vm.u.TablineMenu.index, vm.u.TablineMenu.event); - break; - default: - // unrecognised message, ignore it - break; + else + add_to_input_buf(string, len); } + break; + case VimMsg::Resize: + gui_resize_shell(vm.u.NewSize.width, vm.u.NewSize.height); + break; + case VimMsg::ScrollBar: + { + /* + * If loads of scroll messages queue up, use only the last + * one. Always report when the scrollbar stops dragging. + * This is not perfect yet anyway: these events are queued + * yet again, this time in the keyboard input buffer. + */ + int32 oldCount = + atomic_add(&vm.u.Scroll.sb->scrollEventCount, -1); + if (oldCount <= 1 || !vm.u.Scroll.stillDragging) + gui_drag_scrollbar(vm.u.Scroll.sb->getGsb(), + vm.u.Scroll.value, vm.u.Scroll.stillDragging); + } + break; +#if defined(FEAT_MENU) + case VimMsg::Menu: + gui_menu_cb(vm.u.Menu.guiMenu); + break; +#endif + case VimMsg::Mouse: + { + int32 oldCount; + if (vm.u.Mouse.button == MOUSE_DRAG) + oldCount = + atomic_add(&gui.vimTextArea->mouseDragEventCount, -1); + else + oldCount = 0; + if (oldCount <= 1) + gui_send_mouse_event(vm.u.Mouse.button, vm.u.Mouse.x, + vm.u.Mouse.y, vm.u.Mouse.repeated_click, + vm.u.Mouse.modifiers); + } + break; + case VimMsg::MouseMoved: + { + gui_mouse_moved(vm.u.MouseMoved.x, vm.u.MouseMoved.y); + } + break; + case VimMsg::Focus: + gui.in_focus = vm.u.Focus.active; + // XXX Signal that scrollbar dragging has stopped? + // This is needed because we don't get a MouseUp if + // that happens while outside the window... :-( + if (gui.dragged_sb) { + gui.dragged_sb = SBAR_NONE; + } + // gui_update_cursor(TRUE, FALSE); + break; + case VimMsg::Refs: + ::RefsReceived(vm.u.Refs.message, vm.u.Refs.changedir); + break; + case VimMsg::Tabline: + send_tabline_event(vm.u.Tabline.index); + break; + case VimMsg::TablineMenu: + send_tabline_menu_event(vm.u.TablineMenu.index, vm.u.TablineMenu.event); + break; + default: + // unrecognised message, ignore it + break; } + } - /* - * If size < B_OK, it is an error code. - */ - return size; + /* + * If size < B_OK, it is an error code. + */ + return size; } /* @@ -3183,42 +3186,42 @@ gui_haiku_process_event(bigtime_t timeout) * If there is no window, don't call Lock() but do succeed. */ - int + int vim_lock_screen() { - return !gui.vimWindow || gui.vimWindow->Lock(); + return !gui.vimWindow || gui.vimWindow->Lock(); } - void + void vim_unlock_screen() { - if (gui.vimWindow) - gui.vimWindow->Unlock(); + if (gui.vimWindow) + gui.vimWindow->Unlock(); } #define RUN_BAPPLICATION_IN_NEW_THREAD 0 #if RUN_BAPPLICATION_IN_NEW_THREAD - int32 + int32 run_vimapp(void *args) { - VimApp app(appsig); + VimApp app(appsig); - gui.vimApp = &app; - app.Run(); // Run until Quit() called + gui.vimApp = &app; + app.Run(); // Run until Quit() called - return 0; + return 0; } #else - int32 + int32 call_main(void *args) { - struct MainArgs *ma = (MainArgs *)args; + struct MainArgs *ma = (MainArgs *)args; - return main(ma->argc, ma->argv); + return main(ma->argc, ma->argv); } #endif @@ -3227,251 +3230,251 @@ call_main(void *args) * deleted from argv, and *argc is decremented accordingly. This is called * when vim is started, whether or not the GUI has been started. */ - void + void gui_mch_prepare( - int *argc, - char **argv) + int *argc, + char **argv) { - /* - * We don't have any command line arguments for the BeOS GUI yet, - * but this is an excellent place to create our Application object. - */ - if (!gui.vimApp) { - thread_info tinfo; - get_thread_info(find_thread(NULL), &tinfo); + /* + * We don't have any command line arguments for the BeOS GUI yet, + * but this is an excellent place to create our Application object. + */ + if (!gui.vimApp) { + thread_info tinfo; + get_thread_info(find_thread(NULL), &tinfo); - // May need the port very early on to process RefsReceived() - gui.vdcmp = create_port(B_MAX_PORT_COUNT, "vim VDCMP"); + // May need the port very early on to process RefsReceived() + gui.vdcmp = create_port(B_MAX_PORT_COUNT, "vim VDCMP"); #if RUN_BAPPLICATION_IN_NEW_THREAD - thread_id tid = spawn_thread(run_vimapp, "vim VimApp", - tinfo.priority, NULL); - if (tid >= B_OK) { - resume_thread(tid); - } else { - getout(1); - } + thread_id tid = spawn_thread(run_vimapp, "vim VimApp", + tinfo.priority, NULL); + if (tid >= B_OK) { + resume_thread(tid); + } else { + getout(1); + } #else - MainArgs ma = { *argc, argv }; - thread_id tid = spawn_thread(call_main, "vim main()", - tinfo.priority, &ma); - if (tid >= B_OK) { - VimApp app(appsig); + MainArgs ma = { *argc, argv }; + thread_id tid = spawn_thread(call_main, "vim main()", + tinfo.priority, &ma); + if (tid >= B_OK) { + VimApp app(appsig); - gui.vimApp = &app; - resume_thread(tid); - /* - * This is rather horrible. - * call_main will call main() again... - * There will be no infinite recursion since - * gui.vimApp is set now. - */ - app.Run(); // Run until Quit() called - // fprintf(stderr, "app.Run() returned...\n"); - status_t dummy_exitcode; - (void)wait_for_thread(tid, &dummy_exitcode); + gui.vimApp = &app; + resume_thread(tid); + /* + * This is rather horrible. + * call_main will call main() again... + * There will be no infinite recursion since + * gui.vimApp is set now. + */ + app.Run(); // Run until Quit() called + // fprintf(stderr, "app.Run() returned...\n"); + status_t dummy_exitcode; + (void)wait_for_thread(tid, &dummy_exitcode); - /* - * This path should be the normal one taken to exit Vim. - * The main() thread calls mch_exit() which calls - * gui_mch_exit() which terminates its thread. - */ - exit(main_exitcode); - } + /* + * This path should be the normal one taken to exit Vim. + * The main() thread calls mch_exit() which calls + * gui_mch_exit() which terminates its thread. + */ + exit(main_exitcode); + } #endif - } - // Don't fork() when starting the GUI. Spawned threads are not - // duplicated with a fork(). The result is a mess. - gui.dofork = FALSE; - /* - * XXX Try to determine whether we were started from - * the Tracker or the terminal. - * It would be nice to have this work, because the Tracker - * follows symlinks, so even if you double-click on gvim, - * when it is a link to vim it will still pass a command name - * of vim... - * We try here to see if stdin comes from /dev/null. If so, - * (or if there is an error, which should never happen) start the GUI. - * This does the wrong thing for vim - Run(); // Run() unlocks but does not show + gui.vimWindow->Run(); // Run() unlocks but does not show - // Get the colors from the "Normal" group (set in syntax.c or in a vimrc - // file) - set_normal_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 - */ - gui_check_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 + // Get the colors for the highlight groups (gui_check_colors() might have + // changed them) + highlight_gui_started(); // re-init colors and fonts - gui_mch_new_colors(); // window must exist for this + gui_mch_new_colors(); // window must exist for this - return OK; + return OK; } /* * Called when the foreground or background color has been changed. */ - void + void gui_mch_new_colors() { - rgb_color rgb = GUI_TO_RGB(gui.back_pixel); + rgb_color rgb = GUI_TO_RGB(gui.back_pixel); - if (gui.vimWindow->Lock()) { - gui.vimForm->SetViewColor(rgb); - // Does this not have too much effect for those small rectangles? - gui.vimForm->Invalidate(); - gui.vimWindow->Unlock(); - } + if (gui.vimWindow->Lock()) { + gui.vimForm->SetViewColor(rgb); + // Does this not have too much effect for those small rectangles? + gui.vimForm->Invalidate(); + gui.vimWindow->Unlock(); + } } /* * Open the GUI window which was created by a call to gui_mch_init(). */ - int + int gui_mch_open() { - if (gui_win_x != -1 && gui_win_y != -1) - gui_mch_set_winpos(gui_win_x, gui_win_y); + if (gui_win_x != -1 && gui_win_y != -1) + gui_mch_set_winpos(gui_win_x, gui_win_y); - // Actually open the window - if (gui.vimWindow->Lock()) { - gui.vimWindow->Show(); - gui.vimWindow->Unlock(); - return OK; - } + // Actually open the window + if (gui.vimWindow->Lock()) { + gui.vimWindow->Show(); + gui.vimWindow->Unlock(); + return OK; + } - return FAIL; + return FAIL; } - void + void gui_mch_exit(int vim_exitcode) { - if (gui.vimWindow) { - thread_id tid = gui.vimWindow->Thread(); - gui.vimWindow->Lock(); - gui.vimWindow->Quit(); - // Wait until it is truely gone - int32 exitcode; - wait_for_thread(tid, &exitcode); - } - delete_port(gui.vdcmp); + if (gui.vimWindow) { + thread_id tid = gui.vimWindow->Thread(); + gui.vimWindow->Lock(); + gui.vimWindow->Quit(); + // Wait until it is truely gone + int32 exitcode; + wait_for_thread(tid, &exitcode); + } + delete_port(gui.vdcmp); #if !RUN_BAPPLICATION_IN_NEW_THREAD - /* - * We are in the main() thread - quit the App thread and - * quit ourselves (passing on the exitcode). Use a global since the - * value from exit_thread() is only used if wait_for_thread() is - * called in time (race condition). - */ + /* + * We are in the main() thread - quit the App thread and + * quit ourselves (passing on the exitcode). Use a global since the + * value from exit_thread() is only used if wait_for_thread() is + * called in time (race condition). + */ #endif - if (gui.vimApp) { - VimTextAreaView::guiBlankMouse(false); + if (gui.vimApp) { + VimTextAreaView::guiBlankMouse(false); - main_exitcode = vim_exitcode; + main_exitcode = vim_exitcode; #if RUN_BAPPLICATION_IN_NEW_THREAD - thread_id tid = gui.vimApp->Thread(); - int32 exitcode; - gui.vimApp->Lock(); - gui.vimApp->Quit(); - gui.vimApp->Unlock(); - wait_for_thread(tid, &exitcode); + thread_id tid = gui.vimApp->Thread(); + int32 exitcode; + gui.vimApp->Lock(); + gui.vimApp->Quit(); + gui.vimApp->Unlock(); + wait_for_thread(tid, &exitcode); #else - gui.vimApp->Lock(); - gui.vimApp->Quit(); - gui.vimApp->Unlock(); - // suicide - exit_thread(vim_exitcode); + gui.vimApp->Lock(); + gui.vimApp->Quit(); + gui.vimApp->Unlock(); + // suicide + exit_thread(vim_exitcode); #endif - } - // If we are somehow still here, let mch_exit() handle things. + } + // If we are somehow still here, let mch_exit() handle things. } /* * Get the position of the top left corner of the window. */ - int + int gui_mch_get_winpos(int *x, int *y) { - if (gui.vimWindow->Lock()) { - BRect r; - r = gui.vimWindow->Frame(); - gui.vimWindow->Unlock(); - *x = (int)r.left; - *y = (int)r.top; - return OK; - } - else - return FAIL; + if (gui.vimWindow->Lock()) { + BRect r; + r = gui.vimWindow->Frame(); + gui.vimWindow->Unlock(); + *x = (int)r.left; + *y = (int)r.top; + return OK; + } + else + return FAIL; } /* * Set the position of the top left corner of the window to the given * coordinates. */ - void + void gui_mch_set_winpos(int x, int y) { - if (gui.vimWindow->Lock()) { - gui.vimWindow->MoveTo(x, y); - gui.vimWindow->Unlock(); - } + if (gui.vimWindow->Lock()) { + gui.vimWindow->MoveTo(x, y); + gui.vimWindow->Unlock(); + } } /* @@ -3479,98 +3482,98 @@ 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) // TODO: utilize? + int width, + int height, + int min_width, + int min_height, + int base_width, + int base_height, + int direction) // TODO: utilize? { + /* + * We are basically given the size of the VimForm, if I understand + * correctly. Since it fills the window completely, this will also + * be the size of the window. + */ + if (gui.vimWindow->Lock()) { + gui.vimWindow->ResizeTo(width - PEN_WIDTH, height - PEN_WIDTH); + + // set size limits + float minWidth, maxWidth, minHeight, maxHeight; + + gui.vimWindow->GetSizeLimits(&minWidth, &maxWidth, + &minHeight, &maxHeight); + gui.vimWindow->SetSizeLimits(min_width, maxWidth, + min_height, maxHeight); + /* - * We are basically given the size of the VimForm, if I understand - * correctly. Since it fills the window completely, this will also - * be the size of the window. + * Set the resizing alignment depending on font size. */ - if (gui.vimWindow->Lock()) { - gui.vimWindow->ResizeTo(width - PEN_WIDTH, height - PEN_WIDTH); + gui.vimWindow->SetWindowAlignment( + B_PIXEL_ALIGNMENT, // window_alignment mode, + 1, // int32 h, + 0, // int32 hOffset = 0, + gui.char_width, // int32 width = 0, + base_width, // int32 widthOffset = 0, + 1, // int32 v = 0, + 0, // int32 vOffset = 0, + gui.char_height, // int32 height = 0, + base_height // int32 heightOffset = 0 + ); - // set size limits - float minWidth, maxWidth, minHeight, maxHeight; - - gui.vimWindow->GetSizeLimits(&minWidth, &maxWidth, - &minHeight, &maxHeight); - gui.vimWindow->SetSizeLimits(min_width, maxWidth, - min_height, maxHeight); - - /* - * Set the resizing alignment depending on font size. - */ - gui.vimWindow->SetWindowAlignment( - B_PIXEL_ALIGNMENT, // window_alignment mode, - 1, // int32 h, - 0, // int32 hOffset = 0, - gui.char_width, // int32 width = 0, - base_width, // int32 widthOffset = 0, - 1, // int32 v = 0, - 0, // int32 vOffset = 0, - gui.char_height, // int32 height = 0, - base_height // int32 heightOffset = 0 - ); - - gui.vimWindow->Unlock(); - } + gui.vimWindow->Unlock(); + } } void gui_mch_get_screen_dimensions( - int *screen_w, - int *screen_h) + int *screen_w, + int *screen_h) { - BRect frame; + BRect frame; - { - BScreen screen(gui.vimWindow); + { + BScreen screen(gui.vimWindow); - if (screen.IsValid()) { - frame = screen.Frame(); - } else { - frame.right = 640; - frame.bottom = 480; - } + if (screen.IsValid()) { + frame = screen.Frame(); + } else { + frame.right = 640; + frame.bottom = 480; } + } - // XXX approximations... - *screen_w = (int) frame.right - 2 * gui.scrollbar_width - 20; - *screen_h = (int) frame.bottom - gui.scrollbar_height + // XXX approximations... + *screen_w = (int) frame.right - 2 * gui.scrollbar_width - 20; + *screen_h = (int) frame.bottom - gui.scrollbar_height #ifdef FEAT_MENU - - gui.menu_height + - gui.menu_height #endif - - 30; + - 30; } void gui_mch_set_text_area_pos( - int x, - int y, - int w, - int h) + int x, + int y, + int w, + int h) { - if (!gui.vimTextArea) - return; + if (!gui.vimTextArea) + return; - if (gui.vimWindow->Lock()) { - gui.vimTextArea->MoveTo(x, y); - gui.vimTextArea->ResizeTo(w - PEN_WIDTH, h - PEN_WIDTH); + if (gui.vimWindow->Lock()) { + gui.vimTextArea->MoveTo(x, y); + gui.vimTextArea->ResizeTo(w - PEN_WIDTH, h - PEN_WIDTH); -/*#ifdef FEAT_GUI_TABLINE - if(gui.vimForm->TabLine() != NULL) { - gui.vimForm->TabLine()->ResizeTo(w, gui.vimForm->TablineHeight()); - } +#ifdef FEAT_GUI_TABLINE + if (gui.vimForm->TabLine() != NULL) { + gui.vimForm->TabLine()->ResizeTo(w, gui.vimForm->TablineHeight()); + } #endif // FEAT_GUI_TABLINE - gui.vimWindow->Unlock(); - } + gui.vimWindow->Unlock(); + } } @@ -3580,115 +3583,115 @@ gui_mch_set_text_area_pos( void gui_mch_enable_scrollbar( - scrollbar_T *sb, - int flag) + scrollbar_T *sb, + int flag) { - VimScrollBar *vsb = sb->id; - if (gui.vimWindow->Lock()) { - /* - * This function is supposed to be idempotent, but Show()/Hide() - * is not. Therefore we test if they are needed. - */ - if (flag) { - if (vsb->IsHidden()) { - vsb->Show(); - } - } else { - if (!vsb->IsHidden()) { - vsb->Hide(); - } - } - gui.vimWindow->Unlock(); + VimScrollBar *vsb = sb->id; + if (gui.vimWindow->Lock()) { + /* + * This function is supposed to be idempotent, but Show()/Hide() + * is not. Therefore we test if they are needed. + */ + if (flag) { + if (vsb->IsHidden()) { + vsb->Show(); + } + } else { + if (!vsb->IsHidden()) { + vsb->Hide(); + } } + gui.vimWindow->Unlock(); + } } void gui_mch_set_scrollbar_thumb( - scrollbar_T *sb, - int val, - int size, - int max) + scrollbar_T *sb, + int val, + int size, + int max) { - if (gui.vimWindow->Lock()) { - VimScrollBar *s = sb->id; - if (max == 0) { - s->SetValue(0); - s->SetRange(0.0, 0.0); - } else { - s->SetProportion((float)size / (max + 1.0)); - s->SetSteps(1.0, size > 5 ? size - 2 : size); -#ifndef SCROLL_PAST_END // really only defined in gui.c... - max = max + 1 - size; + if (gui.vimWindow->Lock()) { + VimScrollBar *s = sb->id; + if (max == 0) { + s->SetValue(0); + s->SetRange(0.0, 0.0); + } else { + s->SetProportion((float)size / (max + 1.0)); + s->SetSteps(1.0, size > 5 ? size - 2 : size); +#ifndef SCROLL_PAST_END // really only defined in gui.c... + max = max + 1 - size; #endif - if (max < s->Value()) { - /* - * If the new maximum is lower than the current value, - * setting it would cause the value to be clipped and - * therefore a ValueChanged() call. - * We avoid this by setting the value first, because - * it presumably is <= max. - */ - s->SetValue(val); - s->SetRange(0.0, max); - } else { - /* - * In the other case, set the range first, since the - * new value might be higher than the current max. - */ - s->SetRange(0.0, max); - s->SetValue(val); - } - } - gui.vimWindow->Unlock(); + if (max < s->Value()) { + /* + * If the new maximum is lower than the current value, + * setting it would cause the value to be clipped and + * therefore a ValueChanged() call. + * We avoid this by setting the value first, because + * it presumably is <= max. + */ + s->SetValue(val); + s->SetRange(0.0, max); + } else { + /* + * In the other case, set the range first, since the + * new value might be higher than the current max. + */ + s->SetRange(0.0, max); + s->SetValue(val); + } } + gui.vimWindow->Unlock(); + } } void gui_mch_set_scrollbar_pos( - scrollbar_T *sb, - int x, - int y, - int w, - int h) + scrollbar_T *sb, + int x, + int y, + int w, + int h) { - if (gui.vimWindow->Lock()) { - BRect winb = gui.vimWindow->Bounds(); - float vsbx = x, vsby = y; - VimScrollBar *vsb = sb->id; - vsb->ResizeTo(w - PEN_WIDTH, h - PEN_WIDTH); - if(winb.right-(x+w)MoveTo(vsbx, vsby); - gui.vimWindow->Unlock(); - } + if (gui.vimWindow->Lock()) { + BRect winb = gui.vimWindow->Bounds(); + float vsbx = x, vsby = y; + VimScrollBar *vsb = sb->id; + vsb->ResizeTo(w - PEN_WIDTH, h - PEN_WIDTH); + if (winb.right-(x+w)MoveTo(vsbx, vsby); + gui.vimWindow->Unlock(); + } } void gui_mch_create_scrollbar( - scrollbar_T *sb, - int orient) // SBAR_VERT or SBAR_HORIZ + scrollbar_T *sb, + int orient) // SBAR_VERT or SBAR_HORIZ { - orientation posture = - (orient == SBAR_HORIZ) ? B_HORIZONTAL : B_VERTICAL; + orientation posture = + (orient == SBAR_HORIZ) ? B_HORIZONTAL : B_VERTICAL; - VimScrollBar *vsb = sb->id = new VimScrollBar(sb, posture); - if (gui.vimWindow->Lock()) { - vsb->SetTarget(gui.vimTextArea); - vsb->Hide(); - gui.vimForm->AddChild(vsb); - gui.vimWindow->Unlock(); - } + VimScrollBar *vsb = sb->id = new VimScrollBar(sb, posture); + if (gui.vimWindow->Lock()) { + vsb->SetTarget(gui.vimTextArea); + vsb->Hide(); + gui.vimForm->AddChild(vsb); + gui.vimWindow->Unlock(); + } } -#if defined(FEAT_WINDOWS) || defined(PROTO) +#if defined(FEAT_WINDOWS) || defined(FEAT_GUI_HAIKU) || defined(PROTO) void gui_mch_destroy_scrollbar( - scrollbar_T *sb) + scrollbar_T *sb) { - if (gui.vimWindow->Lock()) { - sb->id->RemoveSelf(); - delete sb->id; - gui.vimWindow->Unlock(); - } + if (gui.vimWindow->Lock()) { + sb->id->RemoveSelf(); + delete sb->id; + gui.vimWindow->Unlock(); + } } #endif @@ -3707,65 +3710,65 @@ gui_mch_is_blink_off(void) * 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 + * 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 int blink_timer = 0; +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 int blink_timer = 0; void gui_mch_set_blinking( - long waittime, - long on, - long off) + long waittime, + long on, + long off) { - // TODO - blink_waittime = waittime; - blink_ontime = on; - blink_offtime = off; + // TODO + 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() + void +gui_mch_stop_blink(int may_call_gui_update_cursor) { - // TODO - if (blink_timer != 0) - { - // XtRemoveTimeOut(blink_timer); - blink_timer = 0; - } - if (blink_state == BLINK_OFF) - gui_update_cursor(TRUE, FALSE); - blink_state = BLINK_NONE; + // TODO + if (blink_timer != 0) + { + // XtRemoveTimeOut(blink_timer); + blink_timer = 0; + } + 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 + void gui_mch_start_blink() { - // TODO - if (blink_timer != 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 = 1; // XtAppAddTimeOut(app_context, blink_waittime, - blink_state = BLINK_ON; - gui_update_cursor(TRUE, FALSE); - } + // TODO + if (blink_timer != 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 = 1; // XtAppAddTimeOut(app_context, blink_waittime, + blink_state = BLINK_ON; + gui_update_cursor(TRUE, FALSE); + } } /* @@ -3774,144 +3777,144 @@ gui_mch_start_blink() */ int gui_mch_init_font( - char_u *font_name, - int fontset) + char_u *font_name, + int fontset) { - if (gui.vimWindow->Lock()) - { - int rc = gui.vimTextArea->mchInitFont(font_name); - gui.vimWindow->Unlock(); + if (gui.vimWindow->Lock()) + { + int rc = gui.vimTextArea->mchInitFont(font_name); + gui.vimWindow->Unlock(); - return rc; - } + return rc; + } - return FAIL; + return FAIL; } - int + int gui_mch_adjust_charsize() { - return FAIL; + return FAIL; } - int + int gui_mch_font_dialog(font_family* family, font_style* style, float* size) { #if defined(FEAT_GUI_DIALOG) - // gui.vimWindow->Unlock(); - VimSelectFontDialog *dialog = new VimSelectFontDialog(family, style, size); - return dialog->Go(); + // gui.vimWindow->Unlock(); + VimSelectFontDialog *dialog = new VimSelectFontDialog(family, style, size); + return dialog->Go(); #else - return NOFONT; + return NOFONT; #endif // FEAT_GUI_DIALOG } GuiFont gui_mch_get_font( - char_u *name, - int giveErrorIfMissing) + char_u *name, + int giveErrorIfMissing) { - static VimFont *fontList = NULL; + static VimFont *fontList = NULL; - if (!gui.in_use) // can't do this when GUI not running - return NOFONT; + if (!gui.in_use) // can't do this when GUI not running + return NOFONT; - // storage for locally modified name; - const int buff_size = B_FONT_FAMILY_LENGTH + B_FONT_STYLE_LENGTH + 20; - static char font_name[buff_size] = {0}; - font_family family = {0}; - font_style style = {0}; - float size = 0.f; + // storage for locally modified name; + const int buff_size = B_FONT_FAMILY_LENGTH + B_FONT_STYLE_LENGTH + 20; + static char font_name[buff_size] = {0}; + font_family family = {0}; + font_style style = {0}; + float size = 0.f; - if (name == 0 && be_fixed_font == 0) { - if(giveErrorIfMissing) - semsg(_(e_font), name); - return NOFONT; + if (name == 0 && be_fixed_font == 0) { + if (giveErrorIfMissing) + semsg(_(e_font), name); + return NOFONT; + } + + bool useSelectGUI = false; + if (name != NULL) + if (STRCMP(name, "*") == 0) { + useSelectGUI = true; + STRNCPY(font_name, hl_get_font_name(), buff_size); + } else + STRNCPY(font_name, name, buff_size); + + if (font_name[0] == 0) { + be_fixed_font->GetFamilyAndStyle(&family, &style); + size = be_fixed_font->Size(); + vim_snprintf(font_name, buff_size, + (char*)"%s/%s/%.0f", family, style, size); + } + + // replace underscores with spaces + char* end = 0; + while (end = strchr((char *)font_name, '_')) + *end = ' '; + + // store the name before strtok corrupt the buffer ;-) + static char buff[buff_size] = {0}; + STRNCPY(buff, font_name, buff_size); + STRNCPY(family, strtok(buff, "/\0"), B_FONT_FAMILY_LENGTH); + char* style_s = strtok(0, "/\0"); + if (style_s != 0) + STRNCPY(style, style_s, B_FONT_STYLE_LENGTH); + size = atof((style_s != 0) ? strtok(0, "/\0") : "0"); + + if (useSelectGUI) { + if (gui_mch_font_dialog(&family, &style, &size) == NOFONT) + return FAIL; + // compose for further processing + vim_snprintf(font_name, buff_size, + (char*)"%s/%s/%.0f", family, style, size); + hl_set_font_name((char_u*)font_name); + + // Set guifont to the name of the selected font. + char_u* new_p_guifont = (char_u*)alloc(STRLEN(font_name) + 1); + if (new_p_guifont != NULL) { + STRCPY(new_p_guifont, 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 = '_'; } + } - bool useSelectGUI = false; - if (name != NULL) - if (STRCMP(name, "*") == 0) { - useSelectGUI = true; - STRNCPY(font_name, hl_get_font_name(), buff_size); - } else - STRNCPY(font_name, name, buff_size); - - if (font_name[0] == 0) { - be_fixed_font->GetFamilyAndStyle(&family, &style); - size = be_fixed_font->Size(); - vim_snprintf(font_name, buff_size, - (char*)"%s/%s/%.0f", family, style, size); + VimFont *flp; + for (flp = fontList; flp; flp = flp->next) { + if (STRCMP(font_name, flp->name) == 0) { + flp->refcount++; + return (GuiFont)flp; } + } - // replace underscores with spaces - char* end = 0; - while (end = strchr((char *)font_name, '_')) - *end = ' '; + VimFont *font = new VimFont(); + font->name = vim_strsave((char_u*)font_name); - // store the name before strtok corrupt the buffer ;-) - static char buff[buff_size] = {0}; - STRNCPY(buff, font_name, buff_size); - STRNCPY(family, strtok(buff, "/\0"), B_FONT_FAMILY_LENGTH); - char* style_s = strtok(0, "/\0"); - if (style_s != 0) - STRNCPY(style, style_s, B_FONT_STYLE_LENGTH); - size = atof((style_s != 0) ? strtok(0, "/\0") : "0"); + if (count_font_styles(family) <= 0) { + if (giveErrorIfMissing) + semsg(_(e_font), font->name); + delete font; + return NOFONT; + } - if (useSelectGUI) { - if(gui_mch_font_dialog(&family, &style, &size) == NOFONT) - return FAIL; - // compose for further processing - vim_snprintf(font_name, buff_size, - (char*)"%s/%s/%.0f", family, style, size); - hl_set_font_name((char_u*)font_name); + // Remember font in the static list for later use + font->next = fontList; + fontList = font; - // Set guifont to the name of the selected font. - char_u* new_p_guifont = alloc(STRLEN(font_name) + 1); - if (new_p_guifont != NULL) { - STRCPY(new_p_guifont, 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 = '_'; - } - } + font->SetFamilyAndStyle(family, style); + if (size > 0.f) + font->SetSize(size); - VimFont *flp; - for (flp = fontList; flp; flp = flp->next) { - if (STRCMP(font_name, flp->name) == 0) { - flp->refcount++; - return (GuiFont)flp; - } - } + font->SetSpacing(B_FIXED_SPACING); + font->SetEncoding(B_UNICODE_UTF8); - VimFont *font = new VimFont(); - font->name = vim_strsave((char_u*)font_name); - - if(count_font_styles(family) <= 0) { - if (giveErrorIfMissing) - semsg(_(e_font), font->name); - delete font; - return NOFONT; - } - - // Remember font in the static list for later use - font->next = fontList; - fontList = font; - - font->SetFamilyAndStyle(family, style); - if(size > 0.f) - font->SetSize(size); - - font->SetSpacing(B_FIXED_SPACING); - font->SetEncoding(B_UNICODE_UTF8); - - return (GuiFont)font; + return (GuiFont)font; } /* @@ -3919,144 +3922,110 @@ gui_mch_get_font( */ void gui_mch_set_font( - GuiFont font) + GuiFont font) { - if (gui.vimWindow->Lock()) { - VimFont *vf = (VimFont *)font; + if (gui.vimWindow->Lock()) { + VimFont *vf = (VimFont *)font; - gui.vimTextArea->SetFont(vf); + gui.vimTextArea->SetFont(vf); - gui.char_width = (int) vf->StringWidth("n"); - font_height fh; - vf->GetHeight(&fh); - gui.char_height = (int)(fh.ascent + 0.9999) - + (int)(fh.descent + 0.9999) + (int)(fh.leading + 0.9999); - gui.char_ascent = (int)(fh.ascent + 0.9999); + gui.char_width = (int) vf->StringWidth("n"); + font_height fh; + vf->GetHeight(&fh); + gui.char_height = (int)(fh.ascent + 0.9999) + + (int)(fh.descent + 0.9999) + (int)(fh.leading + 0.9999); + gui.char_ascent = (int)(fh.ascent + 0.9999); - gui.vimWindow->Unlock(); - } + gui.vimWindow->Unlock(); + } } // XXX TODO This is apparently never called... void gui_mch_free_font( - GuiFont font) + GuiFont font) { - if(font == NOFONT) - return; - VimFont *f = (VimFont *)font; - if (--f->refcount <= 0) { - if (f->refcount < 0) - fprintf(stderr, "VimFont: refcount < 0\n"); - delete f; - } + if (font == NOFONT) + return; + VimFont *f = (VimFont *)font; + if (--f->refcount <= 0) { + if (f->refcount < 0) + fprintf(stderr, "VimFont: refcount < 0\n"); + delete f; + } } - char_u * + char_u * gui_mch_get_fontname(GuiFont font, char_u *name) { - if (name == NULL) - return NULL; - return vim_strsave(name); + if (name == NULL) + return NULL; + return vim_strsave(name); } /* * Adjust gui.char_height (after 'linespace' was changed). */ - int + int gui_mch_adjust_charheight() { - // TODO: linespace support? + // TODO: linespace support? // #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 +// 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 - { - VimFont *font = (VimFont *)gui.norm_font; - font_height fh = {0}; - font->GetHeight(&fh); - gui.char_height = (int)(fh.ascent + fh.descent + 0.5) + p_linespace; - gui.char_ascent = (int)(fh.ascent + 0.5) + p_linespace / 2; - } - return OK; + { + VimFont *font = (VimFont *)gui.norm_font; + font_height fh = {0}; + font->GetHeight(&fh); + gui.char_height = (int)(fh.ascent + fh.descent + 0.5) + p_linespace; + gui.char_ascent = (int)(fh.ascent + 0.5) + p_linespace / 2; + } + return OK; } -/* - * 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 - - void gui_mch_getmouse(int *x, int *y) { - fprintf(stderr, "gui_mch_getmouse"); + fprintf(stderr, "gui_mch_getmouse"); - /*int rootx, rooty, winx, winy; - Window root, child; - unsigned int mask; + /*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; - } + 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 + void gui_mch_mousehide(int hide) { - fprintf(stderr, "gui_mch_getmouse"); - // TODO + fprintf(stderr, "gui_mch_getmouse"); + // TODO } - static int + 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 -1000; + if (isdigit(c)) + return c - '0'; + c = TOLOWER_ASC(c); + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + return -1000; } /* @@ -4067,166 +4036,166 @@ hex_digit(int c) */ guicolor_T gui_mch_get_color( - char_u *name) + char_u *name) { - typedef struct GuiColourTable - { - const char *name; - guicolor_T colour; - } GuiColourTable; + typedef struct GuiColourTable + { + const char *name; + guicolor_T colour; + } GuiColourTable; -#define NSTATIC_COLOURS 50 // 32 -#define NDYNAMIC_COLOURS 33 -#define NCOLOURS (NSTATIC_COLOURS + NDYNAMIC_COLOURS) +#define NSTATIC_COLOURS 50 // 32 +#define NDYNAMIC_COLOURS 33 +#define NCOLOURS (NSTATIC_COLOURS + NDYNAMIC_COLOURS) - static GuiColourTable table[NCOLOURS] = - { - {"Black", RGB(0x00, 0x00, 0x00)}, - {"DarkGray", RGB(0x80, 0x80, 0x80)}, - {"DarkGrey", RGB(0x80, 0x80, 0x80)}, - {"Gray", RGB(0xC0, 0xC0, 0xC0)}, - {"Grey", RGB(0xC0, 0xC0, 0xC0)}, - {"LightGray", RGB(0xD3, 0xD3, 0xD3)}, - {"LightGrey", RGB(0xD3, 0xD3, 0xD3)}, - {"Gray10", RGB(0x1A, 0x1A, 0x1A)}, - {"Grey10", RGB(0x1A, 0x1A, 0x1A)}, - {"Gray20", RGB(0x33, 0x33, 0x33)}, - {"Grey20", RGB(0x33, 0x33, 0x33)}, - {"Gray30", RGB(0x4D, 0x4D, 0x4D)}, - {"Grey30", RGB(0x4D, 0x4D, 0x4D)}, - {"Gray40", RGB(0x66, 0x66, 0x66)}, - {"Grey40", RGB(0x66, 0x66, 0x66)}, - {"Gray50", RGB(0x7F, 0x7F, 0x7F)}, - {"Grey50", RGB(0x7F, 0x7F, 0x7F)}, - {"Gray60", RGB(0x99, 0x99, 0x99)}, - {"Grey60", RGB(0x99, 0x99, 0x99)}, - {"Gray70", RGB(0xB3, 0xB3, 0xB3)}, - {"Grey70", RGB(0xB3, 0xB3, 0xB3)}, - {"Gray80", RGB(0xCC, 0xCC, 0xCC)}, - {"Grey80", RGB(0xCC, 0xCC, 0xCC)}, - {"Gray90", RGB(0xE5, 0xE5, 0xE5)}, - {"Grey90", RGB(0xE5, 0xE5, 0xE5)}, - {"White", RGB(0xFF, 0xFF, 0xFF)}, - {"DarkRed", RGB(0x80, 0x00, 0x00)}, - {"Red", RGB(0xFF, 0x00, 0x00)}, - {"LightRed", RGB(0xFF, 0xA0, 0xA0)}, - {"DarkBlue", RGB(0x00, 0x00, 0x80)}, - {"Blue", RGB(0x00, 0x00, 0xFF)}, - {"LightBlue", RGB(0xA0, 0xA0, 0xFF)}, - {"DarkGreen", RGB(0x00, 0x80, 0x00)}, - {"Green", RGB(0x00, 0xFF, 0x00)}, - {"LightGreen", RGB(0xA0, 0xFF, 0xA0)}, - {"DarkCyan", RGB(0x00, 0x80, 0x80)}, - {"Cyan", RGB(0x00, 0xFF, 0xFF)}, - {"LightCyan", RGB(0xA0, 0xFF, 0xFF)}, - {"DarkMagenta", RGB(0x80, 0x00, 0x80)}, - {"Magenta", RGB(0xFF, 0x00, 0xFF)}, - {"LightMagenta", RGB(0xFF, 0xA0, 0xFF)}, - {"Brown", RGB(0x80, 0x40, 0x40)}, - {"Yellow", RGB(0xFF, 0xFF, 0x00)}, - {"LightYellow", RGB(0xFF, 0xFF, 0xA0)}, - {"DarkYellow", RGB(0xBB, 0xBB, 0x00)}, - {"SeaGreen", RGB(0x2E, 0x8B, 0x57)}, - {"Orange", RGB(0xFF, 0xA5, 0x00)}, - {"Purple", RGB(0xA0, 0x20, 0xF0)}, - {"SlateBlue", RGB(0x6A, 0x5A, 0xCD)}, - {"Violet", RGB(0xEE, 0x82, 0xEE)}, - // NOTE: some entries are zero-allocated for NDDYNAMIC_COLORS - // in this table! - }; + static GuiColourTable table[NCOLOURS] = + { + {"Black", RGB(0x00, 0x00, 0x00)}, + {"DarkGray", RGB(0x80, 0x80, 0x80)}, + {"DarkGrey", RGB(0x80, 0x80, 0x80)}, + {"Gray", RGB(0xC0, 0xC0, 0xC0)}, + {"Grey", RGB(0xC0, 0xC0, 0xC0)}, + {"LightGray", RGB(0xD3, 0xD3, 0xD3)}, + {"LightGrey", RGB(0xD3, 0xD3, 0xD3)}, + {"Gray10", RGB(0x1A, 0x1A, 0x1A)}, + {"Grey10", RGB(0x1A, 0x1A, 0x1A)}, + {"Gray20", RGB(0x33, 0x33, 0x33)}, + {"Grey20", RGB(0x33, 0x33, 0x33)}, + {"Gray30", RGB(0x4D, 0x4D, 0x4D)}, + {"Grey30", RGB(0x4D, 0x4D, 0x4D)}, + {"Gray40", RGB(0x66, 0x66, 0x66)}, + {"Grey40", RGB(0x66, 0x66, 0x66)}, + {"Gray50", RGB(0x7F, 0x7F, 0x7F)}, + {"Grey50", RGB(0x7F, 0x7F, 0x7F)}, + {"Gray60", RGB(0x99, 0x99, 0x99)}, + {"Grey60", RGB(0x99, 0x99, 0x99)}, + {"Gray70", RGB(0xB3, 0xB3, 0xB3)}, + {"Grey70", RGB(0xB3, 0xB3, 0xB3)}, + {"Gray80", RGB(0xCC, 0xCC, 0xCC)}, + {"Grey80", RGB(0xCC, 0xCC, 0xCC)}, + {"Gray90", RGB(0xE5, 0xE5, 0xE5)}, + {"Grey90", RGB(0xE5, 0xE5, 0xE5)}, + {"White", RGB(0xFF, 0xFF, 0xFF)}, + {"DarkRed", RGB(0x80, 0x00, 0x00)}, + {"Red", RGB(0xFF, 0x00, 0x00)}, + {"LightRed", RGB(0xFF, 0xA0, 0xA0)}, + {"DarkBlue", RGB(0x00, 0x00, 0x80)}, + {"Blue", RGB(0x00, 0x00, 0xFF)}, + {"LightBlue", RGB(0xA0, 0xA0, 0xFF)}, + {"DarkGreen", RGB(0x00, 0x80, 0x00)}, + {"Green", RGB(0x00, 0xFF, 0x00)}, + {"LightGreen", RGB(0xA0, 0xFF, 0xA0)}, + {"DarkCyan", RGB(0x00, 0x80, 0x80)}, + {"Cyan", RGB(0x00, 0xFF, 0xFF)}, + {"LightCyan", RGB(0xA0, 0xFF, 0xFF)}, + {"DarkMagenta", RGB(0x80, 0x00, 0x80)}, + {"Magenta", RGB(0xFF, 0x00, 0xFF)}, + {"LightMagenta", RGB(0xFF, 0xA0, 0xFF)}, + {"Brown", RGB(0x80, 0x40, 0x40)}, + {"Yellow", RGB(0xFF, 0xFF, 0x00)}, + {"LightYellow", RGB(0xFF, 0xFF, 0xA0)}, + {"DarkYellow", RGB(0xBB, 0xBB, 0x00)}, + {"SeaGreen", RGB(0x2E, 0x8B, 0x57)}, + {"Orange", RGB(0xFF, 0xA5, 0x00)}, + {"Purple", RGB(0xA0, 0x20, 0xF0)}, + {"SlateBlue", RGB(0x6A, 0x5A, 0xCD)}, + {"Violet", RGB(0xEE, 0x82, 0xEE)}, + // NOTE: some entries are zero-allocated for NDDYNAMIC_COLORS + // in this table! + }; - static int endColour = NSTATIC_COLOURS; - static int newColour = NSTATIC_COLOURS; + static int endColour = NSTATIC_COLOURS; + static int newColour = NSTATIC_COLOURS; - int r, g, b; - int i; + int r, g, b; + int i; - if (name[0] == '#' && STRLEN(name) == 7) - { - // Name is in "#rrggbb" format - r = hex_digit(name[1]) * 16 + hex_digit(name[2]); - g = hex_digit(name[3]) * 16 + hex_digit(name[4]); - b = hex_digit(name[5]) * 16 + hex_digit(name[6]); - if (r < 0 || g < 0 || b < 0) - return INVALCOLOR; - return RGB(r, g, b); - } - else - { - // Check if the name is one of the colours we know - for (i = 0; i < endColour; i++) - if (STRICMP(name, table[i].name) == 0) - return table[i].colour; - } + if (name[0] == '#' && STRLEN(name) == 7) + { + // Name is in "#rrggbb" format + r = hex_digit(name[1]) * 16 + hex_digit(name[2]); + g = hex_digit(name[3]) * 16 + hex_digit(name[4]); + b = hex_digit(name[5]) * 16 + hex_digit(name[6]); + if (r < 0 || g < 0 || b < 0) + return INVALCOLOR; + return RGB(r, g, b); + } + else + { + // Check if the name is one of the colours we know + for (i = 0; i < endColour; i++) + if (STRICMP(name, table[i].name) == 0) + return table[i].colour; + } - /* - * Last attempt. Look in the file "$VIMRUNTIME/rgb.txt". - */ - { + /* + * Last attempt. Look in the file "$VIMRUNTIME/rgb.txt". + */ + { #define LINE_LEN 100 - FILE *fd; - char line[LINE_LEN]; - char_u *fname; + FILE *fd; + char line[LINE_LEN]; + char_u *fname; - fname = expand_env_save((char_u *)"$VIMRUNTIME/rgb.txt"); - if (fname == NULL) - return INVALCOLOR; + 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) - return INVALCOLOR; + fd = fopen((char *)fname, "rt"); + vim_free(fname); + if (fd == NULL) + return INVALCOLOR; - while (!feof(fd)) - { - int len; - int pos; - char *colour; + while (!feof(fd)) + { + int len; + int pos; + char *colour; - fgets(line, LINE_LEN, fd); - len = strlen(line); + fgets(line, LINE_LEN, fd); + len = strlen(line); - if (len <= 1 || line[len-1] != '\n') - continue; + if (len <= 1 || line[len-1] != '\n') + continue; - line[len-1] = '\0'; + line[len-1] = '\0'; - i = sscanf(line, "%d %d %d %n", &r, &g, &b, &pos); - if (i != 3) - continue; + i = sscanf(line, "%d %d %d %n", &r, &g, &b, &pos); + if (i != 3) + continue; - colour = line + pos; - - if (STRICMP(colour, name) == 0) - { - fclose(fd); - /* - * Now remember this colour in the table. - * A LRU scheme might be better but this is simpler. - * Or could use a growing array. - */ - guicolor_T gcolour = RGB(r,g,b); - - // NOTE: see note above in table allocation! We are working here with - // dynamically allocated names, not constant ones! - vim_free((char*)table[newColour].name); - table[newColour].name = (char *)vim_strsave((char_u *)colour); - table[newColour].colour = gcolour; - - newColour++; - if (newColour >= NCOLOURS) - newColour = NSTATIC_COLOURS; - if (endColour < NCOLOURS) - endColour = newColour; - - return gcolour; - } - } + colour = line + pos; + if (STRICMP(colour, name) == 0) + { fclose(fd); + /* + * Now remember this colour in the table. + * A LRU scheme might be better but this is simpler. + * Or could use a growing array. + */ + guicolor_T gcolour = RGB(r,g,b); + + // NOTE: see note above in table allocation! We are working here with + // dynamically allocated names, not constant ones! + vim_free((char*)table[newColour].name); + table[newColour].name = (char *)vim_strsave((char_u *)colour); + table[newColour].colour = gcolour; + + newColour++; + if (newColour >= NCOLOURS) + newColour = NSTATIC_COLOURS; + if (endColour < NCOLOURS) + endColour = newColour; + + return gcolour; + } } - return INVALCOLOR; + fclose(fd); + } + + return INVALCOLOR; } /* @@ -4234,13 +4203,13 @@ gui_mch_get_color( */ void gui_mch_set_fg_color( - guicolor_T color) + guicolor_T color) { - rgb_color rgb = GUI_TO_RGB(color); - if (gui.vimWindow->Lock()) { - gui.vimTextArea->SetHighColor(rgb); - gui.vimWindow->Unlock(); - } + rgb_color rgb = GUI_TO_RGB(color); + if (gui.vimWindow->Lock()) { + gui.vimTextArea->SetHighColor(rgb); + gui.vimWindow->Unlock(); + } } /* @@ -4248,39 +4217,39 @@ gui_mch_set_fg_color( */ void gui_mch_set_bg_color( - guicolor_T color) + guicolor_T color) { - rgb_color rgb = GUI_TO_RGB(color); - if (gui.vimWindow->Lock()) { - gui.vimTextArea->SetLowColor(rgb); - gui.vimWindow->Unlock(); - } + rgb_color rgb = GUI_TO_RGB(color); + if (gui.vimWindow->Lock()) { + gui.vimTextArea->SetLowColor(rgb); + gui.vimWindow->Unlock(); + } } /* * Set the current text special color. */ - void + void gui_mch_set_sp_color(guicolor_T color) { - // prev_sp_color = color; + // prev_sp_color = color; } void gui_mch_draw_string( - int row, - int col, - char_u *s, - int len, - int flags) + int row, + int col, + char_u *s, + int len, + int flags) { - if (gui.vimWindow->Lock()) { - gui.vimTextArea->mchDrawString(row, col, s, len, flags); - gui.vimWindow->Unlock(); - } + if (gui.vimWindow->Lock()) { + gui.vimTextArea->mchDrawString(row, col, s, len, flags); + gui.vimWindow->Unlock(); + } } - guicolor_T + guicolor_T gui_mch_get_rgb_color(int r, int g, int b) { return gui_get_rgb_color_cmn(r, g, b); @@ -4290,40 +4259,40 @@ gui_mch_get_rgb_color(int r, int g, int b) // Return OK if the key with the termcap name "name" is supported. int gui_mch_haskey( - char_u *name) + char_u *name) { - int i; + int i; - for (i = 0; special_keys[i].BeKeys != 0; i++) - if (name[0] == special_keys[i].vim_code0 && - name[1] == special_keys[i].vim_code1) - return OK; - return FAIL; + for (i = 0; special_keys[i].BeKeys != 0; i++) + if (name[0] == special_keys[i].vim_code0 && + name[1] == special_keys[i].vim_code1) + return OK; + return FAIL; } - void + void gui_mch_beep() { - ::beep(); + ::beep(); } - void + void gui_mch_flash(int msec) { - // Do a visual beep by reversing the foreground and background colors + // Do a visual beep by reversing the foreground and background colors - if (gui.vimWindow->Lock()) { - BRect rect = gui.vimTextArea->Bounds(); + if (gui.vimWindow->Lock()) { + BRect rect = gui.vimTextArea->Bounds(); - gui.vimTextArea->SetDrawingMode(B_OP_INVERT); - gui.vimTextArea->FillRect(rect); - gui.vimTextArea->Sync(); - snooze(msec * 1000); // wait for a few msec - gui.vimTextArea->FillRect(rect); - gui.vimTextArea->SetDrawingMode(B_OP_COPY); - gui.vimTextArea->Flush(); - gui.vimWindow->Unlock(); - } + gui.vimTextArea->SetDrawingMode(B_OP_INVERT); + gui.vimTextArea->FillRect(rect); + gui.vimTextArea->Sync(); + snooze(msec * 1000); // wait for a few msec + gui.vimTextArea->FillRect(rect); + gui.vimTextArea->SetDrawingMode(B_OP_COPY); + gui.vimTextArea->Flush(); + gui.vimWindow->Unlock(); + } } /* @@ -4331,45 +4300,45 @@ gui_mch_flash(int msec) */ void gui_mch_invert_rectangle( - int r, - int c, - int nr, - int nc) + int r, + int c, + int nr, + int nc) { - BRect rect; - rect.left = FILL_X(c); - rect.top = FILL_Y(r); - rect.right = rect.left + nc * gui.char_width - PEN_WIDTH; - rect.bottom = rect.top + nr * gui.char_height - PEN_WIDTH; + BRect rect; + rect.left = FILL_X(c); + rect.top = FILL_Y(r); + rect.right = rect.left + nc * gui.char_width - PEN_WIDTH; + rect.bottom = rect.top + nr * gui.char_height - PEN_WIDTH; - if (gui.vimWindow->Lock()) { - gui.vimTextArea->SetDrawingMode(B_OP_INVERT); - gui.vimTextArea->FillRect(rect); - gui.vimTextArea->SetDrawingMode(B_OP_COPY); - gui.vimWindow->Unlock(); - } + if (gui.vimWindow->Lock()) { + gui.vimTextArea->SetDrawingMode(B_OP_INVERT); + gui.vimTextArea->FillRect(rect); + gui.vimTextArea->SetDrawingMode(B_OP_COPY); + gui.vimWindow->Unlock(); + } } /* * Iconify the GUI window. */ - void + void gui_mch_iconify() { - if (gui.vimWindow->Lock()) { - gui.vimWindow->Minimize(true); - gui.vimWindow->Unlock(); - } + if (gui.vimWindow->Lock()) { + gui.vimWindow->Minimize(true); + gui.vimWindow->Unlock(); + } } #if defined(FEAT_EVAL) || defined(PROTO) /* * Bring the Vim window to the foreground. */ - void + void gui_mch_set_foreground(void) { - // TODO + // TODO } #endif @@ -4378,36 +4347,36 @@ gui_mch_set_foreground(void) */ void gui_mch_settitle( - char_u *title, - char_u *icon) + char_u *title, + char_u *icon) { - if (gui.vimWindow->Lock()) { - gui.vimWindow->SetTitle((char *)title); - gui.vimWindow->Unlock(); - } + if (gui.vimWindow->Lock()) { + gui.vimWindow->SetTitle((char *)title); + gui.vimWindow->Unlock(); + } } /* * Draw a cursor without focus. */ - void + void gui_mch_draw_hollow_cursor(guicolor_T color) { - gui_mch_set_fg_color(color); + gui_mch_set_fg_color(color); - BRect r; - r.left = FILL_X(gui.col); - r.top = FILL_Y(gui.row); - int cells = utf_off2cells(LineOffset[gui.row] + gui.col, 100); // TODO-TODO - if(cells>=4) cells = 1; - r.right = r.left + cells*gui.char_width - PEN_WIDTH; - r.bottom = r.top + gui.char_height - PEN_WIDTH; + BRect r; + r.left = FILL_X(gui.col); + r.top = FILL_Y(gui.row); + int cells = utf_off2cells(LineOffset[gui.row] + gui.col, 100); // TODO-TODO + if (cells>=4) cells = 1; + r.right = r.left + cells*gui.char_width - PEN_WIDTH; + r.bottom = r.top + gui.char_height - PEN_WIDTH; - if (gui.vimWindow->Lock()) { - gui.vimTextArea->StrokeRect(r); - gui.vimWindow->Unlock(); - // gui_mch_flush(); - } + if (gui.vimWindow->Lock()) { + gui.vimTextArea->StrokeRect(r); + gui.vimWindow->Unlock(); + // gui_mch_flush(); + } } /* @@ -4415,28 +4384,28 @@ gui_mch_draw_hollow_cursor(guicolor_T color) */ void gui_mch_draw_part_cursor( - int w, - int h, - guicolor_T color) + int w, + int h, + guicolor_T color) { - gui_mch_set_fg_color(color); + gui_mch_set_fg_color(color); - BRect r; - r.left = + BRect r; + r.left = #ifdef FEAT_RIGHTLEFT - // vertical line should be on the right of current point - CURSOR_BAR_RIGHT ? FILL_X(gui.col + 1) - w : + // vertical line should be on the right of current point + CURSOR_BAR_RIGHT ? FILL_X(gui.col + 1) - w : #endif - FILL_X(gui.col); - r.right = r.left + w - PEN_WIDTH; - r.bottom = FILL_Y(gui.row + 1) - PEN_WIDTH; - r.top = r.bottom - h + PEN_WIDTH; + FILL_X(gui.col); + r.right = r.left + w - PEN_WIDTH; + r.bottom = FILL_Y(gui.row + 1) - PEN_WIDTH; + r.top = r.bottom - h + PEN_WIDTH; - if (gui.vimWindow->Lock()) { - gui.vimTextArea->FillRect(r); - gui.vimWindow->Unlock(); - // gui_mch_flush(); - } + if (gui.vimWindow->Lock()) { + gui.vimTextArea->FillRect(r); + gui.vimWindow->Unlock(); + // gui_mch_flush(); + } } /* @@ -4445,78 +4414,102 @@ gui_mch_draw_part_cursor( * nothing in the event queue (& no timers pending), then we return * immediately. */ - void + void gui_mch_update() { - gui_mch_flush(); - while (port_count(gui.vdcmp) > 0 && - !vim_is_input_buf_full() && - gui_haiku_process_event(0) >= B_OK) - /* nothing */ ; + gui_mch_flush(); + while (port_count(gui.vdcmp) > 0 && + !vim_is_input_buf_full() && + gui_haiku_process_event(0) >= B_OK) + /* nothing */ ; } /* * 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. + * 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 wtime) { - int focus; - bigtime_t until, timeout; - status_t st; + int focus; + bigtime_t until, timeout; + status_t st; - if (wtime >= 0) { - timeout = wtime * 1000; - until = system_time() + timeout; - } else { - timeout = B_INFINITE_TIMEOUT; - } + if (wtime >= 0) + { + timeout = wtime * 1000; + until = system_time() + timeout; + } + else + timeout = B_INFINITE_TIMEOUT; - focus = gui.in_focus; - for (;;) + focus = gui.in_focus; + for (;;) + { + // Stop or start blinking when focus changes + if (gui.in_focus != focus) { - // 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(); - focus = gui.in_focus; - } - - gui_mch_flush(); - /* - * Don't use gui_mch_update() because then we will spin-lock until a - * char arrives, instead we use gui_haiku_process_event() 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. - */ - st = gui_haiku_process_event(timeout); - - if (input_available()) - return OK; - if (st < B_OK) // includes B_TIMED_OUT - return FAIL; - - /* - * Calculate how much longer we're willing to wait for the - * next event. - */ - if (wtime >= 0) { - timeout = until - system_time(); - if (timeout < 0) - break; - } + if (gui.in_focus) + gui_mch_start_blink(); + else + gui_mch_stop_blink(TRUE); + focus = gui.in_focus; } - return FAIL; + + gui_mch_flush(); + +#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 +# ifdef FEAT_JOB_CHANNEL + if (has_any_channel()) + { + if (wtime < 0 || timeout > 20000) + timeout = 20000; + } + else if (wtime < 0) + timeout = B_INFINITE_TIMEOUT; +# endif +#endif + + /* + * Don't use gui_mch_update() because then we will spin-lock until a + * char arrives, instead we use gui_haiku_process_event() 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. + */ + st = gui_haiku_process_event(timeout); + + if (input_available()) + return OK; + if (st < B_OK) // includes B_TIMED_OUT + return FAIL; + + /* + * Calculate how much longer we're willing to wait for the + * next event. + */ + if (wtime >= 0) + { + timeout = until - system_time(); + if (timeout < 0) + break; + } + } + return FAIL; } @@ -4528,15 +4521,15 @@ gui_mch_wait_for_chars( * Flush any output to the screen. This is typically called before * the app goes to sleep. */ - void + void gui_mch_flush() { - // does this need to lock the window? Apparently not but be safe. - if (gui.vimWindow->Lock()) { - gui.vimWindow->Flush(); - gui.vimWindow->Unlock(); - } - return; + // does this need to lock the window? Apparently not but be safe. + if (gui.vimWindow->Lock()) { + gui.vimWindow->Flush(); + gui.vimWindow->Unlock(); + } + return; } /* @@ -4545,24 +4538,24 @@ gui_mch_flush() */ void gui_mch_clear_block( - int row1, - int col1, - int row2, - int col2) + int row1, + int col1, + int row2, + int col2) { - if (gui.vimWindow->Lock()) { - gui.vimTextArea->mchClearBlock(row1, col1, row2, col2); - gui.vimWindow->Unlock(); - } + if (gui.vimWindow->Lock()) { + gui.vimTextArea->mchClearBlock(row1, col1, row2, col2); + gui.vimWindow->Unlock(); + } } - void + void gui_mch_clear_all() { - if (gui.vimWindow->Lock()) { - gui.vimTextArea->mchClearAll(); - gui.vimWindow->Unlock(); - } + if (gui.vimWindow->Lock()) { + gui.vimTextArea->mchClearAll(); + gui.vimWindow->Unlock(); + } } /* @@ -4571,10 +4564,10 @@ gui_mch_clear_all() */ void gui_mch_delete_lines( - int row, - int num_lines) + int row, + int num_lines) { - gui.vimTextArea->mchDeleteLines(row, num_lines); + gui.vimTextArea->mchDeleteLines(row, num_lines); } /* @@ -4583,10 +4576,10 @@ gui_mch_delete_lines( */ void gui_mch_insert_lines( - int row, - int num_lines) + int row, + int num_lines) { - gui.vimTextArea->mchInsertLines(row, num_lines); + gui.vimTextArea->mchInsertLines(row, num_lines); } #if defined(FEAT_MENU) || defined(PROTO) @@ -4596,24 +4589,24 @@ gui_mch_insert_lines( void gui_mch_enable_menu( - int flag) + int flag) { - if (gui.vimWindow->Lock()) - { - BMenuBar *menubar = gui.vimForm->MenuBar(); - menubar->SetEnabled(flag); - gui.vimWindow->Unlock(); - } + if (gui.vimWindow->Lock()) + { + BMenuBar *menubar = gui.vimForm->MenuBar(); + menubar->SetEnabled(flag); + gui.vimWindow->Unlock(); + } } void gui_mch_set_menu_pos( - int x, - int y, - int w, - int h) + int x, + int y, + int w, + int h) { - // It will be in the right place anyway + // It will be in the right place anyway } /* @@ -4621,72 +4614,72 @@ gui_mch_set_menu_pos( */ void gui_mch_add_menu( - vimmenu_T *menu, - int idx) + vimmenu_T *menu, + int idx) { - vimmenu_T *parent = menu->parent; + vimmenu_T *parent = menu->parent; + + // popup menu - just create it unattached + if (menu_is_popup(menu->name) && parent == NULL) { + BPopUpMenu* popUpMenu = new BPopUpMenu((const char*)menu->name, false, false); + menu->submenu_id = popUpMenu; + menu->id = NULL; + return; + } + + if (!menu_is_menubar(menu->name) + || (parent != NULL && parent->submenu_id == NULL)) + return; + + if (gui.vimWindow->Lock()) + { + // Major re-write of the menu code, it was failing with memory corruption when + // we started loading multiple files (the Buffer menu) + // + // Note we don't use the preference values yet, all are inserted into the + // menubar on a first come-first served basis... + // + // richard@whitequeen.com jul 99 + + BMenu *tmp; + + if ( parent ) + tmp = parent->submenu_id; + else + tmp = gui.vimForm->MenuBar(); + // make sure we don't try and add the same menu twice. The Buffers menu tries to + // do this and Be starts to crash... + + if ( ! tmp->FindItem((const char *) menu->dname)) { + + BMenu *bmenu = new BMenu((char *)menu->dname); + + menu->submenu_id = bmenu; + + // when we add a BMenu to another Menu, it creates the interconnecting BMenuItem + tmp->AddItem(bmenu); + + // Now its safe to query the menu for the associated MenuItem.... + menu->id = tmp->FindItem((const char *) menu->dname); - // popup menu - just create it unattached - if (menu_is_popup(menu->name) && parent == NULL) { - BPopUpMenu* popUpMenu = new BPopUpMenu((const char*)menu->name, false, false); - menu->submenu_id = popUpMenu; - menu->id = NULL; - return; - } - - if (!menu_is_menubar(menu->name) - || (parent != NULL && parent->submenu_id == NULL)) - return; - - if (gui.vimWindow->Lock()) - { - // Major re-write of the menu code, it was failing with memory corruption when - // we started loading multiple files (the Buffer menu) - // - // Note we don't use the preference values yet, all are inserted into the - // menubar on a first come-first served basis... - // - // richard@whitequeen.com jul 99 - - BMenu *tmp; - - if ( parent ) - tmp = parent->submenu_id; - else - tmp = gui.vimForm->MenuBar(); - // make sure we don't try and add the same menu twice. The Buffers menu tries to - // do this and Be starts to crash... - - if ( ! tmp->FindItem((const char *) menu->dname)) { - - BMenu *bmenu = new BMenu((char *)menu->dname); - - menu->submenu_id = bmenu; - - // when we add a BMenu to another Menu, it creates the interconnecting BMenuItem - tmp->AddItem(bmenu); - - // Now its safe to query the menu for the associated MenuItem.... - menu->id = tmp->FindItem((const char *) menu->dname); - - } - gui.vimWindow->Unlock(); } + gui.vimWindow->Unlock(); + } } - void + void gui_mch_toggle_tearoffs(int enable) { - // no tearoff menus + // no tearoff menus } - static BMessage * + static BMessage * MenuMessage(vimmenu_T *menu) { - BMessage *m = new BMessage('menu'); - m->AddPointer("VimMenu", (void *)menu); + BMessage *m = new BMessage('menu'); + m->AddPointer("VimMenu", (void *)menu); - return m; + return m; } /* @@ -4694,48 +4687,48 @@ MenuMessage(vimmenu_T *menu) */ void gui_mch_add_menu_item( - vimmenu_T *menu, - int idx) + vimmenu_T *menu, + int idx) { - int mnemonic = 0; - vimmenu_T *parent = menu->parent; + int mnemonic = 0; + vimmenu_T *parent = menu->parent; - // TODO: use menu->actext - // This is difficult, since on Be, an accelerator must be a single char - // and a lot of Vim ones are the standard VI commands. - // - // Punt for Now... - // richard@whiequeen.com jul 99 - if (gui.vimWindow->Lock()) - { + // TODO: use menu->actext + // This is difficult, since on Be, an accelerator must be a single char + // and a lot of Vim ones are the standard VI commands. + // + // Punt for Now... + // richard@whiequeen.com jul 99 + if (gui.vimWindow->Lock()) + { #ifdef FEAT_TOOLBAR - if(menu_is_toolbar(parent->name)) { - VimToolbar *toolbar = gui.vimForm->ToolBar(); - if(toolbar != NULL) { - toolbar->AddButton(idx, menu); - } - } else + if (menu_is_toolbar(parent->name)) { + VimToolbar *toolbar = gui.vimForm->ToolBar(); + if (toolbar != NULL) { + toolbar->AddButton(idx, menu); + } + } else #endif - if (parent->submenu_id != NULL || menu_is_popup(parent->name)) { - if (menu_is_separator(menu->name)) { - BSeparatorItem *item = new BSeparatorItem(); - parent->submenu_id->AddItem(item); - menu->id = item; - menu->submenu_id = NULL; - } - else { - BMenuItem *item = new BMenuItem((char *)menu->dname, - MenuMessage(menu)); - item->SetTarget(gui.vimTextArea); - item->SetTrigger((char) menu->mnemonic); - parent->submenu_id->AddItem(item); - menu->id = item; - menu->submenu_id = NULL; - } - } - gui.vimWindow->Unlock(); + if (parent->submenu_id != NULL || menu_is_popup(parent->name)) { + if (menu_is_separator(menu->name)) { + BSeparatorItem *item = new BSeparatorItem(); + parent->submenu_id->AddItem(item); + menu->id = item; + menu->submenu_id = NULL; + } + else { + BMenuItem *item = new BMenuItem((char *)menu->dname, + MenuMessage(menu)); + item->SetTarget(gui.vimTextArea); + item->SetTrigger((char) menu->mnemonic); + parent->submenu_id->AddItem(item); + menu->id = item; + menu->submenu_id = NULL; + } } + gui.vimWindow->Unlock(); + } } /* @@ -4743,48 +4736,48 @@ gui_mch_add_menu_item( */ void gui_mch_destroy_menu( - vimmenu_T *menu) + vimmenu_T *menu) { - if (gui.vimWindow->Lock()) - { + if (gui.vimWindow->Lock()) + { #ifdef FEAT_TOOLBAR - if(menu->parent && menu_is_toolbar(menu->parent->name)) { - VimToolbar *toolbar = gui.vimForm->ToolBar(); - if(toolbar != NULL) { - toolbar->RemoveButton(menu); - } - } else + if (menu->parent && menu_is_toolbar(menu->parent->name)) { + VimToolbar *toolbar = gui.vimForm->ToolBar(); + if (toolbar != NULL) { + toolbar->RemoveButton(menu); + } + } else #endif + { + assert(menu->submenu_id == NULL || menu->submenu_id->CountItems() == 0); + /* + * Detach this menu from its parent, so that it is not deleted + * twice once we get to delete that parent. + * Deleting a BMenuItem also deletes the associated BMenu, if any + * (which does not have any items anymore since they were + * removed and deleted before). + */ + BMenu *bmenu = menu->id->Menu(); + if (bmenu) + { + bmenu->RemoveItem(menu->id); + /* + * If we removed the last item from the menu bar, + * resize it out of sight. + */ + if (bmenu == gui.vimForm->MenuBar() && bmenu->CountItems() == 0) { - assert(menu->submenu_id == NULL || menu->submenu_id->CountItems() == 0); - /* - * Detach this menu from its parent, so that it is not deleted - * twice once we get to delete that parent. - * Deleting a BMenuItem also deletes the associated BMenu, if any - * (which does not have any items anymore since they were - * removed and deleted before). - */ - BMenu *bmenu = menu->id->Menu(); - if (bmenu) - { - bmenu->RemoveItem(menu->id); - /* - * If we removed the last item from the menu bar, - * resize it out of sight. - */ - if (bmenu == gui.vimForm->MenuBar() && bmenu->CountItems() == 0) - { - bmenu->ResizeTo(-MENUBAR_MARGIN, -MENUBAR_MARGIN); - } - } - delete menu->id; - menu->id = NULL; - menu->submenu_id = NULL; - - gui.menu_height = (int) gui.vimForm->MenuHeight(); + bmenu->ResizeTo(-MENUBAR_MARGIN, -MENUBAR_MARGIN); } - gui.vimWindow->Unlock(); + } + delete menu->id; + menu->id = NULL; + menu->submenu_id = NULL; + + gui.menu_height = (int) gui.vimForm->MenuHeight(); } + gui.vimWindow->Unlock(); + } } /* @@ -4792,22 +4785,22 @@ gui_mch_destroy_menu( */ void gui_mch_menu_grey( - vimmenu_T *menu, - int grey) + vimmenu_T *menu, + int grey) { #ifdef FEAT_TOOLBAR - if(menu->parent && menu_is_toolbar(menu->parent->name)) { - if (gui.vimWindow->Lock()) { - VimToolbar *toolbar = gui.vimForm->ToolBar(); - if(toolbar != NULL) { - toolbar->GrayButton(menu, grey); - } - gui.vimWindow->Unlock(); - } - } else + if (menu->parent && menu_is_toolbar(menu->parent->name)) { + if (gui.vimWindow->Lock()) { + VimToolbar *toolbar = gui.vimForm->ToolBar(); + if (toolbar != NULL) { + toolbar->GrayButton(menu, grey); + } + gui.vimWindow->Unlock(); + } + } else #endif - if (menu->id != NULL) - menu->id->SetEnabled(!grey); + if (menu->id != NULL) + menu->id->SetEnabled(!grey); } /* @@ -4815,40 +4808,40 @@ gui_mch_menu_grey( */ void gui_mch_menu_hidden( - vimmenu_T *menu, - int hidden) + vimmenu_T *menu, + int hidden) { - if (menu->id != NULL) - menu->id->SetEnabled(!hidden); + if (menu->id != NULL) + menu->id->SetEnabled(!hidden); } /* * This is called after setting all the menus to grey/hidden or not. */ - void + void gui_mch_draw_menubar() { - // Nothing to do in BeOS + // Nothing to do in BeOS } - void + void gui_mch_show_popupmenu(vimmenu_T *menu) { - if (!menu_is_popup(menu->name) || menu->submenu_id == NULL) - return; + if (!menu_is_popup(menu->name) || menu->submenu_id == NULL) + return; - BPopUpMenu* popupMenu = dynamic_cast(menu->submenu_id); - if (popupMenu == NULL) - return; + BPopUpMenu* popupMenu = dynamic_cast(menu->submenu_id); + if (popupMenu == NULL) + return; - BPoint point; - if(gui.vimWindow->Lock()) { - uint32 buttons = 0; - gui.vimTextArea->GetMouse(&point, &buttons); - gui.vimTextArea->ConvertToScreen(&point); - gui.vimWindow->Unlock(); - } - popupMenu->Go(point, true); + BPoint point; + if (gui.vimWindow->Lock()) { + uint32 buttons = 0; + gui.vimTextArea->GetMouse(&point, &buttons); + gui.vimTextArea->ConvertToScreen(&point); + gui.vimWindow->Unlock(); + } + popupMenu->Go(point, true); } #endif // FEAT_MENU @@ -4865,122 +4858,122 @@ char vimselectiontype[] = "application/x-vnd.Rhialto-Vim-selectiontype"; /* * Get the current selection and put it in the clipboard register. */ - void + void clip_mch_request_selection(Clipboard_T *cbd) { - if (be_clipboard->Lock()) + if (be_clipboard->Lock()) + { + BMessage *m = be_clipboard->Data(); + // m->PrintToStream(); + + char_u *string = NULL; + ssize_t stringlen = -1; + + if (m->FindData(textplain, B_MIME_TYPE, + (const void **)&string, &stringlen) == B_OK + || m->FindString("text", (const char **)&string) == B_OK) { - BMessage *m = be_clipboard->Data(); - // m->PrintToStream(); + if (stringlen == -1) + stringlen = STRLEN(string); - char_u *string = NULL; - ssize_t stringlen = -1; + int type; + char *seltype; + ssize_t seltypelen; - if (m->FindData(textplain, B_MIME_TYPE, - (const void **)&string, &stringlen) == B_OK - || m->FindString("text", (const char **)&string) == B_OK) + /* + * Try to get the special vim selection type first + */ + if (m->FindData(vimselectiontype, B_MIME_TYPE, + (const void **)&seltype, &seltypelen) == B_OK) + { + switch (*seltype) { - if (stringlen == -1) - stringlen = STRLEN(string); - - int type; - char *seltype; - ssize_t seltypelen; - - /* - * Try to get the special vim selection type first - */ - if (m->FindData(vimselectiontype, B_MIME_TYPE, - (const void **)&seltype, &seltypelen) == B_OK) - { - switch (*seltype) - { - default: - case 'L': type = MLINE; break; - case 'C': type = MCHAR; break; + default: + case 'L': type = MLINE; break; + case 'C': type = MCHAR; break; #ifdef FEAT_VISUAL - case 'B': type = MBLOCK; break; + case 'B': type = MBLOCK; break; #endif - } - } - else - { - // Otherwise use heuristic as documented - type = memchr(string, stringlen, '\n') ? MLINE : MCHAR; - } - clip_yank_selection(type, string, (long)stringlen, cbd); } - be_clipboard->Unlock(); + } + else + { + // Otherwise use heuristic as documented + type = memchr(string, stringlen, '\n') ? MLINE : MCHAR; + } + clip_yank_selection(type, string, (long)stringlen, cbd); } + be_clipboard->Unlock(); + } } /* * Make vim the owner of the current selection. */ - void + void clip_mch_lose_selection(Clipboard_T *cbd) { - // Nothing needs to be done here + // Nothing needs to be done here } /* * Make vim the owner of the current selection. Return OK upon success. */ - int + int clip_mch_own_selection(Clipboard_T *cbd) { - /* - * Never actually own the clipboard. If another application sets the - * clipboard, we don't want to think that we still own it. - */ - return FAIL; + /* + * Never actually own the clipboard. If another application sets the + * clipboard, we don't want to think that we still own it. + */ + return FAIL; } /* * Send the current selection to the clipboard. */ - void + void clip_mch_set_selection(Clipboard_T *cbd) { - if (be_clipboard->Lock()) + if (be_clipboard->Lock()) + { + be_clipboard->Clear(); + BMessage *m = be_clipboard->Data(); + assert(m); + + // If the '*' register isn't already filled in, fill it in now + cbd->owned = TRUE; + clip_get_selection(cbd); + cbd->owned = FALSE; + + char_u *str = NULL; + long_u count; + int type; + + type = clip_convert_selection(&str, &count, cbd); + + if (type < 0) + return; + + m->AddData(textplain, B_MIME_TYPE, (void *)str, count); + + // Add type of selection + char vtype; + switch (type) { - be_clipboard->Clear(); - BMessage *m = be_clipboard->Data(); - assert(m); - - // If the '*' register isn't already filled in, fill it in now - cbd->owned = TRUE; - clip_get_selection(cbd); - cbd->owned = FALSE; - - char_u *str = NULL; - long_u count; - int type; - - type = clip_convert_selection(&str, &count, cbd); - - if (type < 0) - return; - - m->AddData(textplain, B_MIME_TYPE, (void *)str, count); - - // Add type of selection - char vtype; - switch (type) - { - default: - case MLINE: vtype = 'L'; break; - case MCHAR: vtype = 'C'; break; + default: + case MLINE: vtype = 'L'; break; + case MCHAR: vtype = 'C'; break; #ifdef FEAT_VISUAL - case MBLOCK: vtype = 'B'; break; + case MBLOCK: vtype = 'B'; break; #endif - } - m->AddData(vimselectiontype, B_MIME_TYPE, (void *)&vtype, 1); - - vim_free(str); - - be_clipboard->Commit(); - be_clipboard->Unlock(); } + m->AddData(vimselectiontype, B_MIME_TYPE, (void *)&vtype, 1); + + vim_free(str); + + be_clipboard->Commit(); + be_clipboard->Unlock(); + } } #endif // FEAT_CLIPBOARD @@ -5006,42 +4999,42 @@ clip_mch_set_selection(Clipboard_T *cbd) */ char_u * gui_mch_browse( - int saving, - char_u *title, - char_u *dflt, - char_u *ext, - char_u *initdir, - char_u *filter) + int saving, + char_u *title, + char_u *dflt, + char_u *ext, + char_u *initdir, + char_u *filter) { - gui.vimApp->fFilePanel = new BFilePanel((saving == TRUE) ? B_SAVE_PANEL : B_OPEN_PANEL, - NULL, NULL, 0, false, - new BMessage((saving == TRUE) ? 'save' : 'open'), NULL, true); + gui.vimApp->fFilePanel = new BFilePanel((saving == TRUE) ? B_SAVE_PANEL : B_OPEN_PANEL, + NULL, NULL, 0, false, + new BMessage((saving == TRUE) ? 'save' : 'open'), NULL, true); - gui.vimApp->fBrowsedPath.Unset(); + gui.vimApp->fBrowsedPath.Unset(); - gui.vimApp->fFilePanel->Window()->SetTitle((char*)title); - gui.vimApp->fFilePanel->SetPanelDirectory((const char*)initdir); + gui.vimApp->fFilePanel->Window()->SetTitle((char*)title); + gui.vimApp->fFilePanel->SetPanelDirectory((const char*)initdir); - gui.vimApp->fFilePanel->Show(); + gui.vimApp->fFilePanel->Show(); - gui.vimApp->fFilePanelSem = create_sem(0, "FilePanelSem"); + gui.vimApp->fFilePanelSem = create_sem(0, "FilePanelSem"); - while(acquire_sem(gui.vimApp->fFilePanelSem) == B_INTERRUPTED); + while (acquire_sem(gui.vimApp->fFilePanelSem) == B_INTERRUPTED); - char_u *fileName = NULL; - status_t result = gui.vimApp->fBrowsedPath.InitCheck(); - if(result == B_OK) { - fileName = vim_strsave((char_u*)gui.vimApp->fBrowsedPath.Path()); - } else - if(result != B_NO_INIT) { - fprintf(stderr, "gui_mch_browse: BPath error: %#08x (%s)\n", - result, strerror(result)); - } + char_u *fileName = NULL; + status_t result = gui.vimApp->fBrowsedPath.InitCheck(); + if (result == B_OK) { + fileName = vim_strsave((char_u*)gui.vimApp->fBrowsedPath.Path()); + } else + if (result != B_NO_INIT) { + fprintf(stderr, "gui_mch_browse: BPath error: %#08x (%s)\n", + result, strerror(result)); + } - delete gui.vimApp->fFilePanel; - gui.vimApp->fFilePanel = NULL; + delete gui.vimApp->fFilePanel; + gui.vimApp->fFilePanel = NULL; - return fileName; + return fileName; } #endif // FEAT_BROWSE @@ -5050,34 +5043,34 @@ gui_mch_browse( /* * 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. + * 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. + * 2 for the second, etc. * - * 0 indicates Esc was pressed. - * -1 for unexpected error + * 0 indicates Esc was pressed. + * -1 for unexpected error * * If stubbing out this fn, return 1. */ int gui_mch_dialog( - int type, - char_u *title, - char_u *message, - char_u *buttons, - int dfltbutton, - char_u *textfield, - int ex_cmd) + int type, + char_u *title, + char_u *message, + char_u *buttons, + int dfltbutton, + char_u *textfield, + int ex_cmd) { - VimDialog *dialog = new VimDialog(type, (char*)title, (char*)message, - (char*)buttons, dfltbutton, (char*)textfield, ex_cmd); - return dialog->Go(); + VimDialog *dialog = new VimDialog(type, (char*)title, (char*)message, + (char*)buttons, dfltbutton, (char*)textfield, ex_cmd); + return dialog->Go(); } #endif // FEAT_GUI_DIALOG @@ -5089,50 +5082,50 @@ gui_mch_dialog( guicolor_T gui_mch_get_rgb(guicolor_T pixel) { - rgb_color rgb = GUI_TO_RGB(pixel); + rgb_color rgb = GUI_TO_RGB(pixel); - return ((rgb.red & 0xff) << 16) + ((rgb.green & 0xff) << 8) - + (rgb.blue & 0xff); + return ((rgb.red & 0xff) << 16) + ((rgb.green & 0xff) << 8) + + (rgb.blue & 0xff); } - void + void gui_mch_setmouse(int x, int y) { - TRACE(); - // TODO + TRACE(); + // TODO } #ifdef FEAT_MBYTE_IME - void + void im_set_position(int row, int col) { - if(gui.vimWindow->Lock()) - { - gui.vimTextArea->DrawIMString(); - gui.vimWindow->Unlock(); - } - return; + if (gui.vimWindow->Lock()) + { + gui.vimTextArea->DrawIMString(); + gui.vimWindow->Unlock(); + } + return; } #endif - void + void gui_mch_show_toolbar(int showit) { - VimToolbar *toolbar = gui.vimForm->ToolBar(); - gui.toolbar_height = (toolbar && showit) ? toolbar->ToolbarHeight() : 0.; + VimToolbar *toolbar = gui.vimForm->ToolBar(); + gui.toolbar_height = (toolbar && showit) ? toolbar->ToolbarHeight() : 0.; } - void + void gui_mch_set_toolbar_pos(int x, int y, int w, int h) { - VimToolbar *toolbar = gui.vimForm->ToolBar(); - if(toolbar != NULL) { - if (gui.vimWindow->Lock()) { - toolbar->MoveTo(x, y); - toolbar->ResizeTo(w - 1, h - 1); - gui.vimWindow->Unlock(); - } + VimToolbar *toolbar = gui.vimForm->ToolBar(); + if (toolbar != NULL) { + if (gui.vimWindow->Lock()) { + toolbar->MoveTo(x, y); + toolbar->ResizeTo(w - 1, h - 1); + gui.vimWindow->Unlock(); } + } } #if defined(FEAT_GUI_TABLINE) || defined(PROTO) @@ -5143,28 +5136,28 @@ gui_mch_set_toolbar_pos(int x, int y, int w, int h) void gui_mch_show_tabline(int showit) { - VimTabLine *tabLine = gui.vimForm->TabLine(); + VimTabLine *tabLine = gui.vimForm->TabLine(); if (tabLine == NULL) - return; + return; if (!showit != !gui.vimForm->IsShowingTabLine()) { - gui.vimForm->SetShowingTabLine(showit != 0); - gui.tabline_height = gui.vimForm->TablineHeight(); + gui.vimForm->SetShowingTabLine(showit != 0); + gui.tabline_height = gui.vimForm->TablineHeight(); } } - void + void gui_mch_set_tabline_pos(int x, int y, int w, int h) { - VimTabLine *tabLine = gui.vimForm->TabLine(); - if(tabLine != NULL) { - if (gui.vimWindow->Lock()) { - tabLine->MoveTo(x, y); - tabLine->ResizeTo(w - 1, h - 1); - gui.vimWindow->Unlock(); - } + VimTabLine *tabLine = gui.vimForm->TabLine(); + if (tabLine != NULL) { + if (gui.vimWindow->Lock()) { + tabLine->MoveTo(x, y); + tabLine->ResizeTo(w - 1, h - 1); + gui.vimWindow->Unlock(); } + } } /* @@ -5173,7 +5166,7 @@ gui_mch_set_tabline_pos(int x, int y, int w, int h) int gui_mch_showing_tabline() { - VimTabLine *tabLine = gui.vimForm->TabLine(); + VimTabLine *tabLine = gui.vimForm->TabLine(); return tabLine != NULL && gui.vimForm->IsShowingTabLine(); } @@ -5184,41 +5177,41 @@ gui_mch_showing_tabline() gui_mch_update_tabline() { tabpage_T *tp; - int nr = 0; - int curtabidx = 0; + int nr = 0; + int curtabidx = 0; - VimTabLine *tabLine = gui.vimForm->TabLine(); + VimTabLine *tabLine = gui.vimForm->TabLine(); if (tabLine == NULL) - return; + return; - gui.vimWindow->Lock(); + gui.vimWindow->Lock(); // 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 (tp == curtab) + curtabidx = nr; - BTab* tab = tabLine->TabAt(nr); + BTab* tab = tabLine->TabAt(nr); - if (tab == NULL) { - tab = new VimTabLine::VimTab(); - tabLine->AddTab(NULL, tab); - } + if (tab == NULL) { + tab = new VimTabLine::VimTab(); + tabLine->AddTab(NULL, tab); + } - get_tabline_label(tp, FALSE); - tab->SetLabel((const char*)NameBuff); - tabLine->Invalidate(); + get_tabline_label(tp, FALSE); + tab->SetLabel((const char*)NameBuff); + tabLine->Invalidate(); } // Remove any old labels. - while (nr < tabLine->CountTabs()) - tabLine->RemoveTab(nr); + while (nr < tabLine->CountTabs()) + tabLine->RemoveTab(nr); - if(tabLine->Selection() != curtabidx) - tabLine->Select(curtabidx); + if (tabLine->Selection() != curtabidx) + tabLine->Select(curtabidx); - gui.vimWindow->Unlock(); + gui.vimWindow->Unlock(); } /* @@ -5227,16 +5220,16 @@ gui_mch_update_tabline() void gui_mch_set_curtab(int nr) { - VimTabLine *tabLine = gui.vimForm->TabLine(); - if(tabLine == NULL) - return; + VimTabLine *tabLine = gui.vimForm->TabLine(); + if (tabLine == NULL) + return; - gui.vimWindow->Lock(); + gui.vimWindow->Lock(); - if(tabLine->Selection() != nr -1) - tabLine->Select(nr -1); + if (tabLine->Selection() != nr -1) + tabLine->Select(nr -1); - gui.vimWindow->Unlock(); + gui.vimWindow->Unlock(); } #endif // FEAT_GUI_TABLINE diff --git a/src/gui_mac.c b/src/gui_mac.c index 81ed47ca39..5b4c2e6362 100644 --- a/src/gui_mac.c +++ b/src/gui_mac.c @@ -2168,9 +2168,9 @@ gui_mac_unicode_key_event( // taken liberally from gui_w48.c key_char = simplify_key(key_char, (int *)&vimModifiers); - // Interpret META, include SHIFT, etc. + // Unify modifiers somewhat. No longer use ALT to set the 8th bit. key_char = extract_modifiers(key_char, (int *)&vimModifiers, - TRUE, NULL); + FALSE, NULL); if (key_char == CSI) key_char = K_CSI; diff --git a/src/gui_motif.c b/src/gui_motif.c index 022626bcb0..90c5df98d6 100644 --- a/src/gui_motif.c +++ b/src/gui_motif.c @@ -1238,8 +1238,11 @@ add_pixmap_args(vimmenu_T *menu, Arg *args, int n) } else { +# if 0 // DISABLED - this causes a crash when running "make test_gui" in + // Test_colorscheme() if (menu->xpm_fname != NULL) XtSetArg(args[n], XmNpixmapFile, menu->xpm_fname); n++; +# endif XtSetArg(args[n], XmNpixmapData, menu->xpm); n++; XtSetArg(args[n], XmNlabelLocation, XmBOTTOM); n++; } diff --git a/src/gui_w32.c b/src/gui_w32.c index 2409ee68e4..6527b42309 100644 --- a/src/gui_w32.c +++ b/src/gui_w32.c @@ -847,8 +847,8 @@ _OnSysChar( 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, TRUE, NULL); + // Unify modifiers somewhat. No longer use ALT to set the 8th bit. + ch = extract_modifiers(ch, &modifiers, FALSE, NULL); if (ch == CSI) ch = K_CSI; diff --git a/src/gui_x11.c b/src/gui_x11.c index f05de7bac8..1eec793e5a 100644 --- a/src/gui_x11.c +++ b/src/gui_x11.c @@ -771,8 +771,8 @@ gui_x11_key_hit_cb( #else char_u string[4], string2[3]; #endif - KeySym key_sym, key_sym2; - int len, len2; + KeySym key_sym; + int len; int i; int modifiers; int key; @@ -883,57 +883,9 @@ gui_x11_key_hit_cb( } #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 , 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; - } + // We used to apply Alt/Meta to the key here (Mod1Mask), but that is now + // done later, the same as it happens for the terminal. Hopefully that + // works for everybody... if (len == 1 && string[0] == CSI) { @@ -963,54 +915,52 @@ gui_x11_key_hit_cb( 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))) + // Handle modifiers. + 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)) { - 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; + string[0] = CSI; + string[1] = K_SECOND(key); + string[2] = K_THIRD(key); + len = 3; + } + else + { + string[0] = key; + len = 1; - /* - * 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; - } + // Remove the SHIFT modifier for keys where it's already included, + // e.g., '(', '!' and '*'. + if (!ASCII_ISALPHA(key) && key > 0x20 && key < 0x7f) + modifiers &= ~MOD_MASK_SHIFT; + } - if (modifiers != 0) - { - string2[0] = CSI; - string2[1] = KS_MODIFIER; - string2[2] = modifiers; - add_to_input_buf(string2, 3); - } + 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) diff --git a/src/highlight.c b/src/highlight.c index d077917a49..89ebee355c 100644 --- a/src/highlight.c +++ b/src/highlight.c @@ -524,7 +524,7 @@ static int color_numbers_88[28] = {0, 4, 2, 6, 75, 11, 78, 15, -1}; // for xterm with 256 colors... static int color_numbers_256[28] = {0, 4, 2, 6, - 1, 5, 130, 130, + 1, 5, 130, 3, 248, 248, 7, 7, 242, 242, 12, 81, 10, 121, @@ -658,7 +658,7 @@ do_highlight( /* * If no argument, list current highlighting. */ - if (ends_excmd(*line)) + if (!init && ends_excmd2(line - 1, line)) { for (i = 1; i <= highlight_ga.ga_len && !got_int; ++i) // TODO: only call when the group has attributes set @@ -694,7 +694,7 @@ do_highlight( /* * ":highlight {group-name}": list highlighting for one group. */ - if (!doclear && !dolink && ends_excmd(*linep)) + if (!doclear && !dolink && ends_excmd2(line, linep)) { id = syn_namen2id(line, (int)(name_end - line)); if (id == 0) @@ -720,14 +720,14 @@ do_highlight( to_start = skipwhite(from_end); to_end = skiptowhite(to_start); - if (ends_excmd(*from_start) || ends_excmd(*to_start)) + if (ends_excmd2(line, from_start) || ends_excmd2(line, to_start)) { semsg(_("E412: Not enough arguments: \":highlight link %s\""), from_start); return; } - if (!ends_excmd(*skipwhite(to_end))) + if (!ends_excmd2(line, skipwhite(to_end))) { semsg(_("E413: Too many arguments: \":highlight link %s\""), from_start); return; @@ -781,8 +781,7 @@ do_highlight( /* * ":highlight clear [group]" command. */ - line = linep; - if (ends_excmd(*line)) + if (ends_excmd2(line, linep)) { #ifdef FEAT_GUI // First, we do not destroy the old values, but allocate the new @@ -827,7 +826,7 @@ do_highlight( // It is now Ok to clear out the old data. #endif #ifdef FEAT_EVAL - do_unlet((char_u *)"colors_name", TRUE); + do_unlet((char_u *)"g:colors_name", TRUE); #endif restore_cterm_colors(); @@ -846,6 +845,7 @@ do_highlight( redraw_later_clear(); return; } + line = linep; name_end = skiptowhite(line); linep = skipwhite(name_end); } @@ -889,7 +889,7 @@ do_highlight( } if (!doclear) - while (!ends_excmd(*linep)) + while (!ends_excmd2(line, linep)) { key_start = linep; if (*linep == '=') @@ -3744,7 +3744,7 @@ match_add( listitem_T *li; int i; - range_list_materialize(pos_list); + CHECK_LIST_MATERIALIZE(pos_list); for (i = 0, li = pos_list->lv_first; li != NULL && i < MAXPOSMATCH; i++, li = li->li_next) { @@ -4947,10 +4947,11 @@ ex_match(exarg_T *eap) if (!eap->skip) match_delete(curwin, id, FALSE); - if (ends_excmd(*eap->arg)) + if (ends_excmd2(eap->cmd, eap->arg)) end = eap->arg; else if ((STRNICMP(eap->arg, "none", 4) == 0 - && (VIM_ISWHITE(eap->arg[4]) || ends_excmd(eap->arg[4])))) + && (VIM_ISWHITE(eap->arg[4]) + || ends_excmd2(eap->arg, eap->arg + 4)))) end = eap->arg + 4; else { @@ -4968,7 +4969,7 @@ ex_match(exarg_T *eap) end = skip_regexp(p + 1, *p, TRUE); if (!eap->skip) { - if (*end != NUL && !ends_excmd(*skipwhite(end + 1))) + if (*end != NUL && !ends_excmd2(end, skipwhite(end + 1))) { vim_free(g); eap->errmsg = e_trailing; diff --git a/src/if_lua.c b/src/if_lua.c index 19842912fb..9a3081bb4f 100644 --- a/src/if_lua.c +++ b/src/if_lua.c @@ -119,6 +119,7 @@ static luaV_Funcref *luaV_pushfuncref(lua_State *L, char_u *name); #define luaL_buffinit dll_luaL_buffinit #define luaL_addlstring dll_luaL_addlstring #define luaL_pushresult dll_luaL_pushresult +#define luaL_loadstring dll_luaL_loadstring // lua #if LUA_VERSION_NUM <= 501 #define lua_tonumber dll_lua_tonumber @@ -213,6 +214,7 @@ 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); +int (*dll_luaL_loadstring) (lua_State *L, const char *s); // lua #if LUA_VERSION_NUM <= 501 lua_Number (*dll_lua_tonumber) (lua_State *L, int idx); @@ -325,6 +327,7 @@ static const luaV_Reg luaV_dll[] = { {"luaL_buffinit", (luaV_function) &dll_luaL_buffinit}, {"luaL_addlstring", (luaV_function) &dll_luaL_addlstring}, {"luaL_pushresult", (luaV_function) &dll_luaL_pushresult}, + {"luaL_loadstring", (luaV_function) &dll_luaL_loadstring}, // lua #if LUA_VERSION_NUM <= 501 {"lua_tonumber", (luaV_function) &dll_lua_tonumber}, @@ -568,8 +571,21 @@ luaV_totypval(lua_State *L, int pos, typval_T *tv) break; case LUA_TNUMBER: #ifdef FEAT_FLOAT - tv->v_type = VAR_FLOAT; - tv->vval.v_float = (float_T) lua_tonumber(L, pos); + { + const lua_Number n = lua_tonumber(L, pos); + + if (n > (lua_Number)INT64_MAX || n < (lua_Number)INT64_MIN + || ((lua_Number)((varnumber_T)n)) != n) + { + tv->v_type = VAR_FLOAT; + tv->vval.v_float = (float_T)n; + } + else + { + tv->v_type = VAR_NUMBER; + tv->vval.v_number = (varnumber_T)n; + } + } #else tv->v_type = VAR_NUMBER; tv->vval.v_number = (varnumber_T) lua_tointeger(L, pos); @@ -1903,6 +1919,52 @@ luaV_type(lua_State *L) return 1; } + static int +luaV_call(lua_State *L) +{ + int argc = lua_gettop(L) - 1; + size_t funcname_len; + char_u *funcname; + char *error = NULL; + typval_T rettv; + typval_T argv[MAX_FUNC_ARGS + 1]; + int i = 0; + + if (argc > MAX_FUNC_ARGS) + return luaL_error(L, "Function called with too many arguments"); + + funcname = (char_u *)luaL_checklstring(L, 1, &funcname_len); + + for (; i < argc; i++) + { + if (luaV_totypval(L, i + 2, &argv[i]) == FAIL) + { + error = "lua: cannot convert value"; + goto free_vim_args; + } + } + + argv[argc].v_type = VAR_UNKNOWN; + + if (call_vim_function(funcname, argc, argv, &rettv) == FAIL) + { + error = "lua: call_vim_function failed"; + goto free_vim_args; + } + + luaV_pushtypval(L, &rettv); + clear_tv(&rettv); + +free_vim_args: + while (i > 0) + clear_tv(&argv[--i]); + + if (error == NULL) + return 1; + else + return luaL_error(L, error); +} + static const luaL_Reg luaV_module[] = { {"command", luaV_command}, {"eval", luaV_eval}, @@ -1916,6 +1978,7 @@ static const luaL_Reg luaV_module[] = { {"window", luaV_window}, {"open", luaV_open}, {"type", luaV_type}, + {"call", luaV_call}, {NULL, NULL} }; @@ -1997,6 +2060,17 @@ luaV_setref(lua_State *L) return 1; } +#define LUA_VIM_FN_CODE \ + "vim.fn = setmetatable({}, {"\ + " __index = function (t, key)"\ + " local function _fn(...)"\ + " return vim.call(key, ...)"\ + " end"\ + " t[key] = _fn"\ + " return _fn"\ + " end"\ + "})" + static int luaopen_vim(lua_State *L) { @@ -2052,6 +2126,8 @@ luaopen_vim(lua_State *L) lua_pushvalue(L, 1); // cache table luaV_openlib(L, luaV_module, 1); lua_setglobal(L, LUAVIM_NAME); + // custom code + (void)luaL_dostring(L, LUA_VIM_FN_CODE); return 0; } diff --git a/src/if_py_both.h b/src/if_py_both.h index 5a878bd2bd..9f563f0afd 100644 --- a/src/if_py_both.h +++ b/src/if_py_both.h @@ -652,7 +652,7 @@ VimTryEnd(void) } else if (!did_throw) return (PyErr_Occurred() ? -1 : 0); - // Python exception is preferred over vim one; unlikely to occur though + // Python exception is preferred over Vim one; unlikely to occur though else if (PyErr_Occurred()) { discard_current_exception(); @@ -785,7 +785,7 @@ VimToPython(typval_T *our_tv, int depth, PyObject *lookup_dict) return NULL; } - range_list_materialize(list); + CHECK_LIST_MATERIALIZE(list); FOR_ALL_LIST_ITEMS(list, curr) { if (!(newObj = VimToPython(&curr->li_tv, depth + 1, lookup_dict))) @@ -1406,7 +1406,7 @@ 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"}, + {"bindeval", VimEvalPy, METH_O, "Like eval(), but returns objects attached to Vim ones"}, {"strwidth", VimStrwidth, METH_O, "Screen string width, counts as having width 1"}, {"chdir", (PyCFunction)VimChdir, METH_VARARGS|METH_KEYWORDS, "Change directory"}, {"fchdir", (PyCFunction)VimFchdir, METH_VARARGS|METH_KEYWORDS, "Change directory"}, @@ -2256,7 +2256,7 @@ ListNew(PyTypeObject *subtype, list_T *list) return NULL; self->list = list; ++list->lv_refcount; - range_list_materialize(list); + CHECK_LIST_MATERIALIZE(list); pyll_add((PyObject *)(self), &self->ref, &lastlist); @@ -2393,7 +2393,7 @@ ListIndex(ListObject *self, Py_ssize_t 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"), + PyErr_VIM_FORMAT(N_("internal error: failed to get Vim list item %d"), (int) index); return NULL; } @@ -2555,7 +2555,7 @@ ListAssSlice(ListObject *self, Py_ssize_t first, li = list_find(l, (long) first); if (li == NULL) { - PyErr_VIM_FORMAT(N_("internal error: no vim list item %d"), + PyErr_VIM_FORMAT(N_("internal error: no Vim list item %d"), (int)first); if (obj != NULL) PyMem_Free(lis); @@ -2824,7 +2824,7 @@ ListIter(ListObject *self) return NULL; } - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); list_add_watch(l, &lii->lw); lii->lw.lw_item = l->lv_first; lii->list = l; @@ -2934,7 +2934,7 @@ FunctionNew(PyTypeObject *subtype, char_u *name, int argc, typval_T *argv, if (isdigit(*name)) { - if (!translated_function_exists(name)) + if (!translated_function_exists(name, FALSE)) { PyErr_FORMAT(PyExc_ValueError, N_("unnamed function %s does not exist"), name); @@ -3021,7 +3021,7 @@ FunctionConstructor(PyTypeObject *subtype, PyObject *args, PyObject *kwargs) return NULL; } argslist = argstv.vval.v_list; - range_list_materialize(argslist); + CHECK_LIST_MATERIALIZE(argslist); argc = argslist->lv_len; if (argc != 0) @@ -4267,7 +4267,7 @@ StringToLine(PyObject *obj) /* * Create a copy of the string, with internal nulls replaced by - * newline characters, as is the vim convention. + * newline characters, as is the Vim convention. */ save = alloc(len+1); if (save == NULL) @@ -4614,7 +4614,7 @@ SetBufferLineList( // 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). + // responsibility to Vim in this case). if (!PyErr_Occurred()) { while (i < new_len) @@ -5825,7 +5825,7 @@ run_eval(const char *cmd, typval_T *rettv else { if (ConvertFromPyObject(run_ret, rettv) == -1) - emsg(_("E859: Failed to convert returned python object to vim value")); + emsg(_("E859: Failed to convert returned python object to a Vim value")); Py_DECREF(run_ret); } PyErr_Clear(); @@ -6159,7 +6159,7 @@ ConvertFromPyMapping(PyObject *obj, typval_T *tv) else { PyErr_FORMAT(PyExc_TypeError, - N_("unable to convert %s to vim dictionary"), + N_("unable to convert %s to a Vim dictionary"), Py_TYPE_NAME(obj)); ret = -1; } @@ -6188,7 +6188,7 @@ ConvertFromPySequence(PyObject *obj, typval_T *tv) else { PyErr_FORMAT(PyExc_TypeError, - N_("unable to convert %s to vim list"), + N_("unable to convert %s to a Vim list"), Py_TYPE_NAME(obj)); ret = -1; } @@ -6333,7 +6333,7 @@ _ConvertFromPyObject(PyObject *obj, typval_T *tv, PyObject *lookup_dict) else { PyErr_FORMAT(PyExc_TypeError, - N_("unable to convert %s to vim structure"), + N_("unable to convert %s to a Vim structure"), Py_TYPE_NAME(obj)); return -1; } @@ -6575,7 +6575,7 @@ init_structs(void) 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_doc = "dictionary pushing modifications to Vim structure"; DictionaryType.tp_methods = DictionaryMethods; DictionaryType.tp_iter = (getiterfunc)DictionaryIter; DictionaryType.tp_new = (newfunc)DictionaryConstructor; @@ -6595,7 +6595,7 @@ init_structs(void) 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_doc = "list pushing modifications to Vim structure"; ListType.tp_methods = ListMethods; ListType.tp_iter = (getiterfunc)ListIter; ListType.tp_new = (newfunc)ListConstructor; @@ -6614,7 +6614,7 @@ init_structs(void) 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_doc = "object that calls Vim function"; FunctionType.tp_methods = FunctionMethods; FunctionType.tp_repr = (reprfunc)FunctionRepr; FunctionType.tp_new = (newfunc)FunctionConstructor; diff --git a/src/if_ruby.c b/src/if_ruby.c index e989c01336..6773a2a38a 100644 --- a/src/if_ruby.c +++ b/src/if_ruby.c @@ -100,7 +100,8 @@ #endif // On macOS pre-installed Ruby defines "SIZEOF_TIME_T" as "SIZEOF_LONG" so it -// conflicts with the definition in config.h then causes macro-redifned warning. +// conflicts with the definition in config.h then causes a macro-redefined +// warning. #ifdef SIZEOF_TIME_T # undef SIZEOF_TIME_T #endif @@ -113,6 +114,11 @@ # include // for ST_STOP and ST_CONTINUE #endif +// See above. +#ifdef SIZEOF_TIME_T +# undef SIZEOF_TIME_T +#endif + #undef off_t // ruby defines off_t as _int64, Mingw uses long #undef EXTERN #undef _ diff --git a/src/if_tcl.c b/src/if_tcl.c index 45d880bdad..17e20ee389 100644 --- a/src/if_tcl.c +++ b/src/if_tcl.c @@ -1403,7 +1403,7 @@ vimerror(Tcl_Interp *interp) } else if (did_emsg) { - Tcl_SetResult(interp, _("vim error"), TCL_STATIC); + Tcl_SetResult(interp, _("Vim error"), TCL_STATIC); return TCL_ERROR; } return TCL_OK; diff --git a/src/indent.c b/src/indent.c index 10c82d89de..a1d4d3628e 100644 --- a/src/indent.c +++ b/src/indent.c @@ -1760,7 +1760,7 @@ get_expr_indent(void) set_vim_var_nr(VV_LNUM, curwin->w_cursor.lnum); if (use_sandbox) ++sandbox; - ++textlock; + ++textwinlock; // Need to make a copy, the 'indentexpr' option could be changed while // evaluating it. @@ -1773,7 +1773,7 @@ get_expr_indent(void) if (use_sandbox) --sandbox; - --textlock; + --textwinlock; // 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" diff --git a/src/insexpand.c b/src/insexpand.c index 2ed8a46e31..668f996ef8 100644 --- a/src/insexpand.c +++ b/src/insexpand.c @@ -989,9 +989,9 @@ trigger_complete_changed_event(int cur) dict_set_items_ro(v_event); recursive = TRUE; - textlock++; + textwinlock++; apply_autocmds(EVENT_COMPLETECHANGED, NULL, NULL, FALSE, curbuf); - textlock--; + textwinlock--; recursive = FALSE; dict_free_contents(v_event); @@ -2222,6 +2222,9 @@ expand_by_function( pos = curwin->w_cursor; curwin_save = curwin; curbuf_save = curbuf; + // Lock the text to avoid weird things from happening. Do allow switching + // to another window temporarily. + ++textlock; // Call a function, which returns a list or dict. if (call_vim_function(funcname, 2, args, &rettv) == OK) @@ -2244,6 +2247,7 @@ expand_by_function( break; } } + --textlock; if (curwin_save != curwin || curbuf_save != curbuf) { @@ -2335,7 +2339,7 @@ ins_compl_add_list(list_T *list) int dir = compl_direction; // Go through the List with matches and add each of them. - range_list_materialize(list); + CHECK_LIST_MATERIALIZE(list); FOR_ALL_LIST_ITEMS(list, li) { if (ins_compl_add_tv(&li->li_tv, dir) == OK) @@ -2436,6 +2440,7 @@ set_completion(colnr_T startcol, list_T *list) f_complete(typval_T *argvars, typval_T *rettv UNUSED) { int startcol; + int save_textlock = textlock; if ((State & INSERT) == 0) { @@ -2443,22 +2448,24 @@ f_complete(typval_T *argvars, typval_T *rettv UNUSED) return; } + // "textlock" is set when evaluating 'completefunc' but we can change + // text here. + textlock = 0; + // 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; + else + { + startcol = (int)tv_get_number_chk(&argvars[0], NULL); + if (startcol > 0) + set_completion(startcol - 1, argvars[1].vval.v_list); } - - startcol = (int)tv_get_number_chk(&argvars[0], NULL); - if (startcol <= 0) - return; - - set_completion(startcol - 1, argvars[1].vval.v_list); + textlock = save_textlock; } /* @@ -2517,7 +2524,7 @@ get_complete_info(list_T *what_list, dict_T *retdict) else { what_flag = 0; - range_list_materialize(what_list); + CHECK_LIST_MATERIALIZE(what_list); FOR_ALL_LIST_ITEMS(what_list, item) { char_u *what = tv_get_string(&item->li_tv); diff --git a/src/json.c b/src/json.c index c1c6e85638..2720abfca4 100644 --- a/src/json.c +++ b/src/json.c @@ -20,6 +20,8 @@ static int json_encode_item(garray_T *gap, typval_T *val, int copyID, int options); +static char e_json_error[] = N_("E491: json decode error at '%s'"); + /* * Encode "val" into a JSON format string. * The result is added to "gap" @@ -265,7 +267,7 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID, int options) l->lv_copyID = copyID; ga_append(gap, '['); - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); for (li = l->lv_first; li != NULL && !got_int; ) { if (json_encode_item(gap, &li->li_tv, copyID, @@ -740,7 +742,7 @@ json_decode_item(js_read_T *reader, typval_T *res, int options) retval = json_decode_string(reader, cur_item, *p); else { - emsg(_(e_invarg)); + semsg(_(e_json_error), p); retval = FAIL; } break; @@ -748,7 +750,7 @@ json_decode_item(js_read_T *reader, typval_T *res, int options) case ',': // comma: empty item if ((options & JSON_JS) == 0) { - emsg(_(e_invarg)); + semsg(_(e_json_error), p); retval = FAIL; break; } @@ -778,7 +780,7 @@ json_decode_item(js_read_T *reader, typval_T *res, int options) } if (!VIM_ISDIGIT(*sp)) { - emsg(_(e_invarg)); + semsg(_(e_json_error), p); retval = FAIL; break; } @@ -809,7 +811,7 @@ json_decode_item(js_read_T *reader, typval_T *res, int options) &nr, NULL, 0, TRUE); if (len == 0) { - emsg(_(e_invarg)); + semsg(_(e_json_error), p); retval = FAIL; goto theend; } @@ -962,7 +964,7 @@ item_end: retval = MAYBE; else { - emsg(_(e_invarg)); + semsg(_(e_json_error), p); retval = FAIL; } goto theend; @@ -980,7 +982,7 @@ item_end: retval = MAYBE; else { - emsg(_(e_invarg)); + semsg(_(e_json_error), p); retval = FAIL; } goto theend; @@ -1036,7 +1038,7 @@ item_end: retval = MAYBE; else { - emsg(_(e_invarg)); + semsg(_(e_json_error), p); retval = FAIL; } goto theend; @@ -1055,7 +1057,7 @@ item_end: res->v_type = VAR_SPECIAL; res->vval.v_number = VVAL_NONE; } - emsg(_(e_invarg)); + semsg(_(e_json_error), p); theend: ga_clear(&stack); @@ -1079,7 +1081,7 @@ json_decode_all(js_read_T *reader, typval_T *res, int options) if (ret != OK) { if (ret == MAYBE) - emsg(_(e_invarg)); + semsg(_(e_json_error), reader->js_buf); return FAIL; } json_skip_white(reader); diff --git a/src/libvterm/CONTRIBUTING b/src/libvterm/CONTRIBUTING new file mode 100644 index 0000000000..2100d1e510 --- /dev/null +++ b/src/libvterm/CONTRIBUTING @@ -0,0 +1,22 @@ +How to Contribute +----------------- + +The main resources for this library are: + + Launchpad + https://launchpad.net/libvterm + + Freenode: + ##tty or #tickit on irc.freenode.net + + Email: + Paul "LeoNerd" Evans + + +Bug reports and feature requests can be sent to any of the above resources. + +New features, bug patches, etc.. should in the first instance be discussed via +any of the resources listed above, before starting work on the actual code. +There may be future plans or development already in-progress that could be +affected so it is better to discuss the ideas first before starting work +actually writing any code. diff --git a/src/libvterm/Makefile b/src/libvterm/Makefile index 2fca6ad185..852c97fbe8 100644 --- a/src/libvterm/Makefile +++ b/src/libvterm/Makefile @@ -37,13 +37,13 @@ INCFILES=$(TBLFILES:.tbl=.inc) HFILES_INT=$(sort $(wildcard src/*.h)) $(HFILES) VERSION_MAJOR=0 -VERSION_MINOR=0 +VERSION_MINOR=1 VERSION_CURRENT=0 VERSION_REVISION=0 VERSION_AGE=0 -VERSION=0 +VERSION=$(VERSION_MAJOR).$(VERSION_MINOR) PREFIX=/usr/local BINDIR=$(PREFIX)/bin @@ -66,6 +66,9 @@ src/%.lo: src/%.c $(HFILES_INT) src/encoding/%.inc: src/encoding/%.tbl perl -CSD tbl2inc_c.pl $< >$@ +src/fullwidth.inc: + @perl find-wide-chars.pl >$@ + src/encoding.lo: $(INCFILES) bin/%: bin/%.c $(LIBRARY) @@ -107,15 +110,13 @@ install-bin: $(BINFILES) # DIST CUT -VERSION=$(VERSION_MAJOR).$(VERSION_MINOR) - DISTDIR=libvterm-$(VERSION) distdir: $(INCFILES) mkdir __distdir - cp LICENSE __distdir + cp LICENSE CONTRIBUTING __distdir mkdir __distdir/src - cp src/*.c src/*.h __distdir/src + cp src/*.c src/*.h src/*.inc __distdir/src mkdir __distdir/src/encoding cp src/encoding/*.inc __distdir/src/encoding mkdir __distdir/include diff --git a/src/libvterm/README b/src/libvterm/README index 208066bdeb..3e1ff30a87 100644 --- a/src/libvterm/README +++ b/src/libvterm/README @@ -11,6 +11,9 @@ Modifications: - Convert from C99 to C90. - Other changes to support embedding in Vim. +To find the diff of a libvterm patch edit this URL, changing "999" to the patch +number: + https://bazaar.launchpad.net/~libvterm/libvterm/trunk/diff/999?context=3 To merge in changes from Github, do this: - Commit any pending changes. diff --git a/src/libvterm/doc/seqs.txt b/src/libvterm/doc/seqs.txt index c26dc44990..aa15fec3df 100644 --- a/src/libvterm/doc/seqs.txt +++ b/src/libvterm/doc/seqs.txt @@ -97,6 +97,7 @@ between states. CSI Z = CBT CSI ` = HPA CSI a = HPR + CSI b = REP 123 CSI c = DA, device attributes 123 0 = DA 23 CSI > c = DECSDA @@ -166,8 +167,10 @@ between states. 123 SGR 1 = Bold on SGR 3 = Italic on 123 SGR 4 = Underline single + SGR 4:x = Underline style 123 SGR 5 = Blink on 123 SGR 7 = Reverse on + SGR 8 = Conceal on SGR 9 = Strikethrough on SGR 10-19 = Select font SGR 21 = Underline double @@ -176,6 +179,7 @@ between states. 23 SGR 24 = Underline off 23 SGR 25 = Blink off 23 SGR 27 = Reverse off + SGR 28 = Conceal off SGR 29 = Strikethrough off SGR 30-37 = Foreground ANSI SGR 38 = Foreground alternative palette diff --git a/src/libvterm/find-wide-chars.pl b/src/libvterm/find-wide-chars.pl new file mode 100644 index 0000000000..f7f22051bd --- /dev/null +++ b/src/libvterm/find-wide-chars.pl @@ -0,0 +1,30 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +STDOUT->autoflush(1); + +sub iswide +{ + my ( $cp ) = @_; + return chr($cp) =~ m/\p{East_Asian_Width=Wide}|\p{East_Asian_Width=Fullwidth}/; +} + +my ( $start, $end ); +foreach my $cp ( 0 .. 0x1FFFF ) { + iswide($cp) or next; + + if( defined $end and $end == $cp-1 ) { + # extend the range + $end = $cp; + next; + } + + # start a new range + printf " { %#04x, %#04x },\n", $start, $end if defined $start; + + $start = $end = $cp; +} + +printf " { %#04x, %#04x },\n", $start, $end if defined $start; diff --git a/src/libvterm/include/vterm.h b/src/libvterm/include/vterm.h index 0238226fbf..fe4a6fce82 100644 --- a/src/libvterm/include/vterm.h +++ b/src/libvterm/include/vterm.h @@ -19,6 +19,12 @@ extern "C" { typedef unsigned char uint8_t; typedef unsigned int uint32_t; +#define VTERM_VERSION_MAJOR 0 +#define VTERM_VERSION_MINOR 1 + +#define VTERM_CHECK_VERSION \ + vterm_check_version(VTERM_VERSION_MAJOR, VTERM_VERSION_MINOR) + typedef struct VTerm VTerm; typedef struct VTermState VTermState; typedef struct VTermScreen VTermScreen; @@ -29,9 +35,7 @@ typedef struct { int col; } VTermPos; -/* - * Some small utility functions; we can just keep these static here. - */ +/* some small utility functions; we can just keep these static here */ /* * Order points by on-screen flow order: @@ -56,7 +60,7 @@ typedef struct { int end_col; } VTermRect; -// Return true if the rect "r" contains the point "p". +/* true if the rect contains the point */ int vterm_rect_contains(VTermRect r, VTermPos p); #if defined(DEFINE_INLINES) || USE_INLINE @@ -67,6 +71,7 @@ INLINE int vterm_rect_contains(VTermRect r, VTermPos p) } #endif +/* move a rect */ // 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); @@ -79,20 +84,108 @@ INLINE void vterm_rect_move(VTermRect *rect, int row_delta, int 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 +/** + * Bit-field describing the value of VTermColor.type + */ +typedef enum { + /** + * If the lower bit of `type` is not set, the colour is 24-bit RGB. + */ + VTERM_COLOR_RGB = 0x00, + + /** + * The colour is an index into a palette of 256 colours. + */ + VTERM_COLOR_INDEXED = 0x01, + + /** + * Mask that can be used to extract the RGB/Indexed bit. + */ + VTERM_COLOR_TYPE_MASK = 0x01, + + /** + * If set, indicates that this colour should be the default foreground + * color, i.e. there was no SGR request for another colour. When + * rendering this colour it is possible to ignore "idx" and just use a + * colour that is not in the palette. + */ + VTERM_COLOR_DEFAULT_FG = 0x02, + + /** + * If set, indicates that this colour should be the default background + * color, i.e. there was no SGR request for another colour. A common + * option when rendering this colour is to not render a background at + * all, for example by rendering the window transparently at this spot. + */ + VTERM_COLOR_DEFAULT_BG = 0x04, + + /** + * Mask that can be used to extract the default foreground/background bit. + */ + VTERM_COLOR_DEFAULT_MASK = 0x06 +} VTermColorType; + +/** + * Returns true if the VTERM_COLOR_RGB `type` flag is set, indicating that the + * given VTermColor instance is an indexed colour. + */ +#define VTERM_COLOR_IS_INDEXED(col) \ + (((col)->type & VTERM_COLOR_TYPE_MASK) == VTERM_COLOR_INDEXED) + +/** + * Returns true if the VTERM_COLOR_INDEXED `type` flag is set, indicating that + * the given VTermColor instance is an rgb colour. + */ +#define VTERM_COLOR_IS_RGB(col) \ + (((col)->type & VTERM_COLOR_TYPE_MASK) == VTERM_COLOR_RGB) + +/** + * Returns true if the VTERM_COLOR_DEFAULT_FG `type` flag is set, indicating + * that the given VTermColor instance corresponds to the default foreground + * color. + */ +#define VTERM_COLOR_IS_DEFAULT_FG(col) \ + (!!((col)->type & VTERM_COLOR_DEFAULT_FG)) + +/** + * Returns true if the VTERM_COLOR_DEFAULT_BG `type` flag is set, indicating + * that the given VTermColor instance corresponds to the default background + * color. + */ +#define VTERM_COLOR_IS_DEFAULT_BG(col) \ + (!!((col)->type & VTERM_COLOR_DEFAULT_BG)) typedef struct { + /** + * Tag indicating which member is actually valid. + * Please use the `VTERM_COLOR_IS_*` test macros to check whether a + * particular type flag is set. + */ + uint8_t type; + uint8_t red, green, blue; - uint8_t ansi_index; + + uint8_t index; } VTermColor; +/** + * Constructs a new VTermColor instance representing the given RGB values. + */ +void vterm_color_rgb(VTermColor *col, uint8_t red, uint8_t green, uint8_t blue); + +/** + * Construct a new VTermColor instance representing an indexed color with the + * given index. + */ +void vterm_color_indexed(VTermColor *col, uint8_t idx); + +/** + * Compares two colours. Returns true if the colors are equal, false otherwise. + */ +int vterm_color_is_equal(const VTermColor *a, const VTermColor *b); + typedef enum { - // VTERM_VALUETYPE_NONE = 0 + /* VTERM_VALUETYPE_NONE = 0 */ VTERM_VALUETYPE_BOOL = 1, VTERM_VALUETYPE_INT, VTERM_VALUETYPE_STRING, @@ -101,20 +194,28 @@ typedef enum { VTERM_N_VALUETYPES } VTermValueType; +typedef struct { + const char *str; + size_t len : 30; + unsigned int initial : 1; + unsigned int final : 1; +} VTermStringFragment; + typedef union { int boolean; int number; - char *string; + VTermStringFragment string; VTermColor color; } VTermValue; typedef enum { - // VTERM_ATTR_NONE = 0 + /* 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_CONCEAL, // bool: 8, 28 VTERM_ATTR_STRIKE, // bool: 9, 29 VTERM_ATTR_FONT, // number: 10-19 VTERM_ATTR_FOREGROUND, // color: 30-39 90-97 @@ -124,7 +225,7 @@ typedef enum { } VTermAttr; typedef enum { - // VTERM_PROP_NONE = 0 + /* VTERM_PROP_NONE = 0 */ VTERM_PROP_CURSORVISIBLE = 1, // bool VTERM_PROP_CURSORBLINK, // bool VTERM_PROP_ALTSCREEN, // bool @@ -158,23 +259,35 @@ enum { 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) + 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) + unsigned int doublewidth:1; /* DECDWL or DECDHL line */ + unsigned int doubleheight:2; /* DECDHL line (1=top 2=bottom) */ + unsigned int continuation:1; /* Line is a flow continuation of the previous */ } VTermLineInfo; +/* Copies of VTermState fields that the 'resize' callback might have reason to + * edit. 'resize' callback gets total control of these fields and may + * free-and-reallocate them if required. They will be copied back from the + * struct after the callback has returned. + */ typedef struct { - // libvterm relies on the allocated memory to be zeroed out before it is - // returned by the allocator. + VTermPos pos; /* current cursor position */ +} VTermStateFields; + +typedef struct { + /* libvterm relies on this 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; +void vterm_check_version(int major, int minor); + // Allocate and initialize a new terminal with default allocators. VTerm *vterm_new(int rows, int cols); @@ -194,10 +307,17 @@ void vterm_set_utf8(VTerm *vt, int is_utf8); size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len); +/* Setting output callback will override the buffer logic */ +typedef void VTermOutputCallback(const char *s, size_t len, void *user); +void vterm_output_set_callback(VTerm *vt, VTermOutputCallback *func, void *user); + +/* These buffer functions only work if output callback is NOT set + * These are deprecated and will be removed in a later version */ 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); +/* This too */ size_t vterm_output_read(VTerm *vt, char *buffer, size_t len); int vterm_is_modify_other_keys(VTerm *vt); @@ -216,20 +336,21 @@ 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. +/* 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 +/* 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) @@ -241,8 +362,8 @@ typedef struct { 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 (*osc)(int command, VTermStringFragment frag, void *user); + int (*dcs)(const char *command, size_t commandlen, VTermStringFragment frag, void *user); int (*resize)(int rows, int cols, void *user); } VTermParserCallbacks; @@ -265,7 +386,7 @@ typedef struct { // 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 (*resize)(int rows, int cols, VTermStateFields *fields, void *user); int (*setlineinfo)(int row, const VTermLineInfo *newinfo, const VTermLineInfo *oldinfo, void *user); } VTermStateCallbacks; @@ -282,13 +403,19 @@ typedef struct { // useful to add protocol? } VTermMouseState; +typedef struct { + int (*control)(unsigned char control, void *user); + int (*csi)(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user); + int (*osc)(int command, VTermStringFragment frag, void *user); + int (*dcs)(const char *command, size_t commandlen, VTermStringFragment frag, void *user); +} VTermStateFallbacks; + 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_set_unrecognised_fallbacks(VTermState *state, const VTermStateFallbacks *fallbacks, void *user); void *vterm_state_get_unrecognised_fbdata(VTermState *state); // Initialize the state. @@ -307,6 +434,18 @@ 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); +/** + * Makes sure that the given color `col` is indeed an RGB colour. After this + * function returns, VTERM_COLOR_IS_RGB(col) will return true, while all other + * flags stored in `col->type` will have been reset. + * + * @param state is the VTermState instance from which the colour palette should + * be extracted. + * @param col is a pointer at the VTermColor instance that should be converted + * to an RGB colour. + */ +void vterm_state_convert_color_to_rgb(const VTermState *state, VTermColor *col); + // ------------ // Screen layer // ------------ @@ -317,12 +456,20 @@ typedef struct { unsigned int italic : 1; unsigned int blink : 1; unsigned int reverse : 1; + unsigned int conceal : 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) + 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; +enum { + VTERM_UNDERLINE_OFF, + VTERM_UNDERLINE_SINGLE, + VTERM_UNDERLINE_DOUBLE, + VTERM_UNDERLINE_CURLY, +}; + typedef struct { #define VTERM_MAX_CHARS_PER_CELL 6 uint32_t chars[VTERM_MAX_CHARS_PER_CELL]; @@ -356,8 +503,7 @@ VTermScreen *vterm_obtain_screen(VTerm *vt); 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_set_unrecognised_fallbacks(VTermScreen *screen, const VTermStateFallbacks *fallbacks, void *user); void *vterm_screen_get_unrecognised_fbdata(VTermScreen *screen); // Enable support for using the alternate screen if "altscreen" is non-zero. @@ -366,10 +512,10 @@ void *vterm_screen_get_unrecognised_fbdata(VTermScreen *screen); 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_DAMAGE_CELL, /* every cell */ + VTERM_DAMAGE_ROW, /* entire rows */ + VTERM_DAMAGE_SCREEN, /* entire screen */ + VTERM_DAMAGE_SCROLL, /* entire screen + scrollrect */ VTERM_N_DAMAGES } VTermDamageSize; @@ -385,7 +531,7 @@ void vterm_screen_set_damage_merge(VTermScreen *screen, VTermDamageSize size); */ void vterm_screen_reset(VTermScreen *screen, int hard); -// Neither of these functions NUL-terminate the buffer +/* 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); @@ -399,8 +545,9 @@ typedef enum { VTERM_ATTR_FONT_MASK = 1 << 6, VTERM_ATTR_FOREGROUND_MASK = 1 << 7, VTERM_ATTR_BACKGROUND_MASK = 1 << 8, + VTERM_ATTR_CONCEAL_MASK = 1 << 9, - VTERM_ALL_ATTRS_MASK = (1 << 9) - 1 + VTERM_ALL_ATTRS_MASK = (1 << 10) - 1 } VTermAttrMask; int vterm_screen_get_attrs_extent(const VTermScreen *screen, VTermRect *extent, VTermPos pos, VTermAttrMask attrs); @@ -409,6 +556,12 @@ int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCe int vterm_screen_is_eol(const VTermScreen *screen, VTermPos pos); +/** + * Same as vterm_state_convert_color_to_rgb(), but takes a `screen` instead of a `state` + * instance. + */ +void vterm_screen_convert_color_to_rgb(const VTermScreen *screen, VTermColor *col); + // --------- // Utilities // --------- diff --git a/src/libvterm/src/encoding.c b/src/libvterm/src/encoding.c index 623b14f2ac..694ed6a0ca 100644 --- a/src/libvterm/src/encoding.c +++ b/src/libvterm/src/encoding.c @@ -223,7 +223,7 @@ encodings[] = { { 0, 0, NULL }, }; -// This ought to be INTERNAL but isn't because it's used by unit testing +/* 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; diff --git a/src/libvterm/src/fullwidth.inc b/src/libvterm/src/fullwidth.inc new file mode 100644 index 0000000000..a703529a76 --- /dev/null +++ b/src/libvterm/src/fullwidth.inc @@ -0,0 +1,111 @@ + { 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, 0x4dbf }, + { 0x4e00, 0xa48c }, + { 0xa490, 0xa4c6 }, + { 0xa960, 0xa97c }, + { 0xac00, 0xd7a3 }, + { 0xf900, 0xfaff }, + { 0xfe10, 0xfe19 }, + { 0xfe30, 0xfe52 }, + { 0xfe54, 0xfe66 }, + { 0xfe68, 0xfe6b }, + { 0xff01, 0xff60 }, + { 0xffe0, 0xffe6 }, + { 0x16fe0, 0x16fe3 }, + { 0x17000, 0x187f7 }, + { 0x18800, 0x18af2 }, + { 0x1b000, 0x1b11e }, + { 0x1b150, 0x1b152 }, + { 0x1b164, 0x1b167 }, + { 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 }, + { 0x1f6d5, 0x1f6d5 }, + { 0x1f6eb, 0x1f6ec }, + { 0x1f6f4, 0x1f6fa }, + { 0x1f7e0, 0x1f7eb }, + { 0x1f90d, 0x1f971 }, + { 0x1f973, 0x1f976 }, + { 0x1f97a, 0x1f9a2 }, + { 0x1f9a5, 0x1f9aa }, + { 0x1f9ae, 0x1f9ca }, + { 0x1f9cd, 0x1f9ff }, + { 0x1fa70, 0x1fa73 }, + { 0x1fa78, 0x1fa7a }, + { 0x1fa80, 0x1fa82 }, + { 0x1fa90, 0x1fa95 }, diff --git a/src/libvterm/src/keyboard.c b/src/libvterm/src/keyboard.c index 95b962ed64..87288fe970 100644 --- a/src/libvterm/src/keyboard.c +++ b/src/libvterm/src/keyboard.c @@ -19,8 +19,9 @@ void vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod) return; } - // The shift modifier is never important for Unicode characters - // apart from Space + /* The shift modifier is never important for Unicode characters + * apart from Space + */ if(c != ' ') mod &= ~VTERM_MOD_SHIFT; @@ -33,24 +34,24 @@ void vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod) } switch(c) { - // Special Ctrl- letters that can't be represented elsewise + /* 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 + /* Ctrl-\ ] ^ _ don't need CSUu */ case '\\': case ']': case '^': case '_': needs_CSIu = 0; break; - // Shift-space needs CSIu + /* Shift-space needs CSIu */ case ' ': needs_CSIu = !!(mod & VTERM_MOD_SHIFT); break; - // All other characters needs CSIu except for letters a-z + /* 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 + /* 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; @@ -102,10 +103,10 @@ static keycodes_s keycodes[] = { 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_SS3, 'P', 0 }, // F1 + { KEYCODE_SS3, 'Q', 0 }, // F2 + { KEYCODE_SS3, 'R', 0 }, // F3 + { KEYCODE_SS3, 'S', 0 }, // F4 { KEYCODE_CSINUM, '~', 15 }, // F5 { KEYCODE_CSINUM, '~', 17 }, // F6 { KEYCODE_CSINUM, '~', 18 }, // F7 @@ -165,7 +166,7 @@ void vterm_keyboard_key(VTerm *vt, VTermKey key, VTermModifier mod) break; case KEYCODE_TAB: - // Shift-Tab is CSI Z but plain Tab is 0x09 + /* 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) @@ -175,7 +176,7 @@ void vterm_keyboard_key(VTerm *vt, VTermKey key, VTermModifier mod) break; case KEYCODE_ENTER: - // Enter is CRLF in newline mode, but just LF in linefeed + /* Enter is CRLF in newline mode, but just LF in linefeed */ if(vt->state->mode.newline) vterm_push_output_sprintf(vt, "\r\n"); else diff --git a/src/libvterm/src/mouse.c b/src/libvterm/src/mouse.c index ae74cfc4bb..4e363134eb 100644 --- a/src/libvterm/src/mouse.c +++ b/src/libvterm/src/mouse.c @@ -83,7 +83,7 @@ void vterm_mouse_button(VTerm *vt, int button, int pressed, VTermModifier mod) state->mouse_buttons &= ~(1 << (button-1)); } - // Most of the time we don't get button releases from 4/5 + /* 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)) diff --git a/src/libvterm/src/parser.c b/src/libvterm/src/parser.c index 8a06c427b0..490f5ce1bb 100644 --- a/src/libvterm/src/parser.c +++ b/src/libvterm/src/parser.c @@ -23,10 +23,10 @@ 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(" leader: %s\n", vt->parser.v.csi.leader); + for(int argi = 0; argi < vt->parser.v.csi.argi; argi++) { + printf(" %lu", CSI_ARG(vt->parser.v.csi.args[argi])); + if(!CSI_ARG_HAS_MORE(vt->parser.v.csi.args[argi])) printf("\n"); printf(" intermed: %s\n", vt->parser.intermed); } @@ -34,9 +34,9 @@ static void do_csi(VTerm *vt, char command) 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.v.csi.leaderlen ? vt->parser.v.csi.leader : NULL, + vt->parser.v.csi.args, + vt->parser.v.csi.argi, vt->parser.intermedlen ? vt->parser.intermed : NULL, command, vt->parser.cbdata)) @@ -61,65 +61,36 @@ static void do_escape(VTerm *vt, char command) DEBUG_LOG1("libvterm: Unhandled escape ESC 0x%02x\n", command); } -static void append_strbuffer(VTerm *vt, const char *str, size_t len) +static void string_fragment(VTerm *vt, const char *str, size_t len, int final) { - 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 %zu bytes\n", len); + VTermStringFragment frag; + + frag.str = str; + frag.len = len; + frag.initial = vt->parser.string_initial; + frag.final = final; + + switch(vt->parser.state) { + case OSC: + if(vt->parser.callbacks && vt->parser.callbacks->osc) + (*vt->parser.callbacks->osc)(vt->parser.v.osc.command, frag, vt->parser.cbdata); + break; + + case DCS: + if(len && vt->parser.callbacks && vt->parser.callbacks->dcs) + (*vt->parser.callbacks->dcs)(vt->parser.v.dcs.command, vt->parser.v.dcs.commandlen, frag, vt->parser.cbdata); + break; + + case NORMAL: + case CSI_LEADER: + case CSI_ARGS: + case CSI_INTERMED: + case OSC_COMMAND: + case DCS_COMMAND: + break; } - 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; - } + vt->parser.string_initial = FALSE; } size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len) @@ -135,43 +106,47 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len) case CSI_LEADER: case CSI_ARGS: case CSI_INTERMED: - case ESC: + case OSC_COMMAND: + case DCS_COMMAND: string_start = NULL; break; - case STRING: - case ESC_IN_STRING: + case OSC: + case DCS: 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) +#define IS_STRING_STATE() (vt->parser.state >= OSC_COMMAND) + for( ; pos < len; pos++) { unsigned char c = bytes[pos]; + int c1_allowed = !vt->mode.utf8; + size_t string_len; if(c == 0x00 || c == 0x7f) { // NUL, DEL - if(vt->parser.state >= STRING) { - more_string(vt, string_start, bytes + pos - string_start); + if(IS_STRING_STATE()) { + string_fragment(vt, string_start, bytes + pos - string_start, FALSE); string_start = bytes + pos + 1; } continue; } if(c == 0x18 || c == 0x1a) { // CAN, SUB + vt->parser.in_esc = FALSE; 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); + if(!IS_STRING_STATE()) + vt->parser.state = NORMAL; + vt->parser.in_esc = TRUE; continue; } else if(c == 0x07 && // BEL, can stand for ST in OSC or DCS state - vt->parser.state == STRING) { + IS_STRING_STATE()) { // fallthrough } else if(c < 0x20) { // other C0 @@ -182,96 +157,72 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len) if(pos + 2 < len && bytes[pos + 1] == 0x20 && bytes[pos + 2] == 0x08) vt->in_backspace = 2; // Trigger when count down to 1 } - if(vt->parser.state >= STRING) - more_string(vt, string_start, bytes + pos - string_start); + if(IS_STRING_STATE()) + string_fragment(vt, string_start, bytes + pos - string_start, FALSE); do_control(vt, c); - if(vt->parser.state >= STRING) + if(IS_STRING_STATE()) string_start = bytes + pos + 1; continue; } // else fallthrough + string_len = bytes + pos - string_start; + + if(vt->parser.in_esc) { + // Hoist an ESC letter into a C1 if we're not in a string mode + // Always accept ESC \ == ST even in string mode + if(!vt->parser.intermedlen && + c >= 0x40 && c < 0x60 && + ((!IS_STRING_STATE() || c == 0x5c))) { + c += 0x40; + c1_allowed = TRUE; + string_len -= 1; + vt->parser.in_esc = FALSE; + } + else { + string_start = NULL; + vt->parser.state = NORMAL; + } + } + 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 + /* 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; + if(vt->parser.v.csi.leaderlen < CSI_LEADER_MAX-1) + vt->parser.v.csi.leader[vt->parser.v.csi.leaderlen++] = c; break; } - // else fallthrough - vt->parser.csi_leader[vt->parser.csi_leaderlen] = 0; + /* else fallthrough */ + vt->parser.v.csi.leader[vt->parser.v.csi.leaderlen] = 0; - vt->parser.csi_argi = 0; - vt->parser.csi_args[0] = CSI_ARG_MISSING; + vt->parser.v.csi.argi = 0; + vt->parser.v.csi.args[0] = CSI_ARG_MISSING; vt->parser.state = CSI_ARGS; - // fallthrough + /* fallthrough */ case CSI_ARGS: - // Numerical value of argument + /* 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'; + if(vt->parser.v.csi.args[vt->parser.v.csi.argi] == CSI_ARG_MISSING) + vt->parser.v.csi.args[vt->parser.v.csi.argi] = 0; + vt->parser.v.csi.args[vt->parser.v.csi.argi] *= 10; + vt->parser.v.csi.args[vt->parser.v.csi.argi] += c - '0'; break; } if(c == ':') { - vt->parser.csi_args[vt->parser.csi_argi] |= CSI_ARG_FLAG_MORE; + vt->parser.v.csi.args[vt->parser.v.csi.argi] |= CSI_ARG_FLAG_MORE; c = ';'; } if(c == ';') { - vt->parser.csi_argi++; - vt->parser.csi_args[vt->parser.csi_argi] = CSI_ARG_MISSING; + vt->parser.v.csi.argi++; + vt->parser.v.csi.args[vt->parser.v.csi.argi] = CSI_ARG_MISSING; break; } - // else fallthrough - vt->parser.csi_argi++; + /* else fallthrough */ + vt->parser.v.csi.argi++; vt->parser.intermedlen = 0; vt->parser.state = CSI_INTERMED; // fallthrough @@ -282,42 +233,90 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len) break; } else if(c == 0x1b) { - // ESC in CSI cancels + /* 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 + /* 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(); + case OSC_COMMAND: + /* Numerical value of command */ + if(c >= '0' && c <= '9') { + if(vt->parser.v.osc.command == -1) + vt->parser.v.osc.command = 0; + else + vt->parser.v.osc.command *= 10; + vt->parser.v.osc.command += c - '0'; + break; } - 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); + if(c == ';') { + vt->parser.state = OSC; + string_start = bytes + pos + 1; + break; + } + + /* else fallthrough */ + string_start = bytes + pos; + string_len = 0; + vt->parser.state = OSC; + goto string_state; + + case DCS_COMMAND: + if(vt->parser.v.dcs.commandlen < CSI_LEADER_MAX) + vt->parser.v.dcs.command[vt->parser.v.dcs.commandlen++] = c; + + if(c >= 0x40 && c<= 0x7e) { + string_start = bytes + pos + 1; + vt->parser.state = DCS; + } + break; + +string_state: + case OSC: + case DCS: + if(c == 0x07 || (c1_allowed && c == 0x9c)) { + string_fragment(vt, string_start, string_len, TRUE); + ENTER_NORMAL_STATE(); } break; case NORMAL: - if(c >= 0x80 && c < 0xa0 && !vt->mode.utf8) { + if(vt->parser.in_esc) { + if(is_intermed(c)) { + if(vt->parser.intermedlen < INTERMED_MAX-1) + vt->parser.intermed[vt->parser.intermedlen++] = c; + } + else if(c >= 0x30 && c < 0x7f) { + do_escape(vt, c); + vt->parser.in_esc = 0; + ENTER_NORMAL_STATE(); + } + else { + DEBUG_LOG1("TODO: Unhandled byte %02x in Escape\n", c); + } + break; + } + if(c1_allowed && c >= 0x80 && c < 0xa0) { switch(c) { case 0x90: // DCS - start_string(vt, VTERM_PARSER_DCS); - ENTER_STRING_STATE(); + vt->parser.string_initial = TRUE; + vt->parser.v.dcs.commandlen = 0; + ENTER_STATE(DCS_COMMAND); break; case 0x9b: // CSI + vt->parser.v.csi.leaderlen = 0; ENTER_STATE(CSI_LEADER); break; case 0x9d: // OSC - start_string(vt, VTERM_PARSER_OSC); - ENTER_STRING_STATE(); + vt->parser.v.osc.command = -1; + vt->parser.string_initial = TRUE; + string_start = bytes + pos + 1; + ENTER_STATE(OSC_COMMAND); break; default: do_control(vt, c); @@ -331,7 +330,7 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len) if(!eaten) { DEBUG_LOG("libvterm: Text callback did not consume any input\n"); - // force it to make progress + /* force it to make progress */ eaten = 1; } @@ -341,6 +340,9 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len) } } + if(string_start) + string_fragment(vt, string_start, bytes + pos - string_start, FALSE); + return len; } diff --git a/src/libvterm/src/pen.c b/src/libvterm/src/pen.c index d34599da11..d3738b9191 100644 --- a/src/libvterm/src/pen.c +++ b/src/libvterm/src/pen.c @@ -2,26 +2,34 @@ #include -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 +/** + * Structure used to store RGB triples without the additional metadata stored in + * VTermColor. + */ +typedef struct { + uint8_t red, green, blue; +} VTermRGB; + +static const VTermRGB ansi_colors[] = { + /* R G B */ + { 0, 0, 0 }, // black + { 224, 0, 0 }, // red + { 0, 224, 0 }, // green + { 224, 224, 0 }, // yellow + { 0, 0, 224 }, // blue + { 224, 0, 224 }, // magenta + { 0, 224, 224 }, // cyan + { 224, 224, 224 }, // 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 + { 128, 128, 128 }, // black + { 255, 64, 64 }, // red + { 64, 255, 64 }, // green + { 255, 255, 64 }, // yellow + { 64, 64, 255 }, // blue + { 255, 64, 255 }, // magenta + { 64, 255, 255 }, // cyan + { 255, 255, 255 }, // white for real }; static int ramp6[] = { @@ -34,6 +42,15 @@ static int ramp24[] = { 0x81, 0x8A, 0x94, 0x9E, 0xA8, 0xB2, 0xBC, 0xC6, 0xD0, 0xDA, 0xE4, 0xEE, }; +static void lookup_default_colour_ansi(long idx, VTermColor *col) +{ + vterm_color_rgb( + col, + ansi_colors[idx].red, ansi_colors[idx].green, ansi_colors[idx].blue); + col->index = idx; + col->type = VTERM_COLOR_INDEXED; +} + static int lookup_colour_ansi(const VTermState *state, long index, VTermColor *col) { if(index >= 0 && index < 16) { @@ -54,10 +71,9 @@ static int lookup_colour_palette(const VTermState *state, long index, VTermColor // 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; + vterm_color_rgb(col, ramp6[index/6/6 % 6], + ramp6[index/6 % 6], + ramp6[index % 6]); return TRUE; } @@ -65,10 +81,7 @@ static int lookup_colour_palette(const VTermState *state, long index, VTermColor // 24 greyscales index -= 232; - col->blue = ramp24[index]; - col->green = ramp24[index]; - col->red = ramp24[index]; - col->ansi_index = VTERM_ANSI_INDEX_NONE; + vterm_color_rgb(col, ramp24[index], ramp24[index], ramp24[index]); return TRUE; } @@ -76,25 +89,23 @@ static int lookup_colour_palette(const VTermState *state, long index, VTermColor return FALSE; } -static int lookup_colour(const VTermState *state, int palette, const long args[], int argcount, VTermColor *col, int *index) +static int lookup_colour(const VTermState *state, int palette, const long args[], int argcount, VTermColor *col) { 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; + vterm_color_rgb(col, CSI_ARG(args[0]), CSI_ARG(args[1]), CSI_ARG(args[2])); return 3; case 5: // XTerm 256-colour mode - if(index) - *index = CSI_ARG_OR(args[0], -1); + if (!argcount || CSI_ARG_IS_MISSING(args[0])) { + return argcount ? 1 : 0; + } - lookup_colour_palette(state, argcount ? CSI_ARG_OR(args[0], -1) : -1, col); + lookup_colour_palette(state, args[0], col); return argcount ? 1 : 0; @@ -154,13 +165,12 @@ 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; + vterm_color_rgb(&state->default_fg, 240, 240, 240); + vterm_color_rgb(&state->default_bg, 0, 0, 0); + vterm_state_set_default_colors(state, &state->default_fg, &state->default_bg); for(col = 0; col < 16; col++) - state->colors[col] = ansi_colors[col]; + lookup_default_colour_ansi(col, &state->colors[col]); } INTERNAL void vterm_state_resetpen(VTermState *state) @@ -170,11 +180,10 @@ INTERNAL void vterm_state_resetpen(VTermState *state) 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.conceal = 0; setpenattr_bool(state, VTERM_ATTR_CONCEAL, 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); } @@ -192,6 +201,7 @@ INTERNAL void vterm_state_savepen(VTermState *state, int save) 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_CONCEAL, state->pen.conceal); 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); @@ -199,6 +209,40 @@ INTERNAL void vterm_state_savepen(VTermState *state, int save) } } +void vterm_color_rgb(VTermColor *col, uint8_t red, uint8_t green, uint8_t blue) +{ + col->type = VTERM_COLOR_RGB; + col->red = red; + col->green = green; + col->blue = blue; +} + +void vterm_color_indexed(VTermColor *col, uint8_t idx) +{ + col->type = VTERM_COLOR_INDEXED; + col->index = idx; +} + +int vterm_color_is_equal(const VTermColor *a, const VTermColor *b) +{ + /* First make sure that the two colours are of the same type (RGB/Indexed) */ + if (a->type != b->type) { + return FALSE; + } + + /* Depending on the type inspect the corresponding members */ + if (VTERM_COLOR_IS_INDEXED(a)) { + return a->index == b->index; + } + else if (VTERM_COLOR_IS_RGB(a)) { + return (a->red == b->red) + && (a->green == b->green) + && (a->blue == b->blue); + } + + return 0; +} + void vterm_state_get_default_colors(const VTermState *state, VTermColor *default_fg, VTermColor *default_bg) { *default_fg = state->default_fg; @@ -212,8 +256,15 @@ void vterm_state_get_palette_color(const VTermState *state, int index, VTermColo void vterm_state_set_default_colors(VTermState *state, const VTermColor *default_fg, const VTermColor *default_bg) { + /* Copy the given colors */ state->default_fg = *default_fg; state->default_bg = *default_bg; + + /* Make sure the correct type flags are set */ + state->default_fg.type = (state->default_fg.type & ~VTERM_COLOR_DEFAULT_MASK) + | VTERM_COLOR_DEFAULT_FG; + state->default_bg.type = (state->default_bg.type & ~VTERM_COLOR_DEFAULT_MASK) + | VTERM_COLOR_DEFAULT_BG; } void vterm_state_set_palette_color(VTermState *state, int index, const VTermColor *col) @@ -221,10 +272,18 @@ void vterm_state_set_palette_color(VTermState *state, int index, const VTermColo if(index >= 0 && index < 16) { state->colors[index] = *col; - state->colors[index].ansi_index = index + VTERM_ANSI_INDEX_MIN; + state->colors[index].index = index + 1; } } +void vterm_state_convert_color_to_rgb(const VTermState *state, VTermColor *col) +{ + if (VTERM_COLOR_IS_INDEXED(col)) { /* Convert indexed colors to RGB */ + lookup_colour_palette(state, col->index, col); + } + col->type &= VTERM_COLOR_TYPE_MASK; /* Reset any metadata but the type */ +} + void vterm_state_set_bold_highbright(VTermState *state, int bold_is_highbright) { state->bold_is_highbright = bold_is_highbright; @@ -249,21 +308,40 @@ INTERNAL void vterm_state_setpen(VTermState *state, const long args[], int argco vterm_state_resetpen(state); break; - case 1: // Bold on + case 1: { // Bold on + const VTermColor *fg = &state->pen.fg; 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)); + if(!VTERM_COLOR_IS_DEFAULT_FG(fg) && VTERM_COLOR_IS_INDEXED(fg) && fg->index < 8 && state->bold_is_highbright) + set_pen_col_ansi(state, VTERM_ATTR_FOREGROUND, 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); + case 4: // Underline + state->pen.underline = VTERM_UNDERLINE_SINGLE; + if(CSI_ARG_HAS_MORE(args[argi])) { + argi++; + switch(CSI_ARG(args[argi])) { + case 0: + state->pen.underline = 0; + break; + case 1: + state->pen.underline = VTERM_UNDERLINE_SINGLE; + break; + case 2: + state->pen.underline = VTERM_UNDERLINE_DOUBLE; + break; + case 3: + state->pen.underline = VTERM_UNDERLINE_CURLY; + break; + } + } + setpenattr_int(state, VTERM_ATTR_UNDERLINE, state->pen.underline); break; case 5: // Blink @@ -276,6 +354,11 @@ INTERNAL void vterm_state_setpen(VTermState *state, const long args[], int argco setpenattr_bool(state, VTERM_ATTR_REVERSE, 1); break; + case 8: // Conceal on + state->pen.conceal = 1; + setpenattr_bool(state, VTERM_ATTR_CONCEAL, 1); + break; + case 9: // Strikethrough on state->pen.strike = 1; setpenattr_bool(state, VTERM_ATTR_STRIKE, 1); @@ -288,8 +371,8 @@ INTERNAL void vterm_state_setpen(VTermState *state, const long args[], int argco break; case 21: // Underline double - state->pen.underline = 2; - setpenattr_int(state, VTERM_ATTR_UNDERLINE, 2); + state->pen.underline = VTERM_UNDERLINE_DOUBLE; + setpenattr_int(state, VTERM_ATTR_UNDERLINE, state->pen.underline); break; case 22: // Bold off @@ -317,6 +400,11 @@ INTERNAL void vterm_state_setpen(VTermState *state, const long args[], int argco setpenattr_bool(state, VTERM_ATTR_REVERSE, 0); break; + case 28: // Conceal off (Reveal) + state->pen.conceal = 0; + setpenattr_bool(state, VTERM_ATTR_CONCEAL, 0); + break; + case 29: // Strikethrough off state->pen.strike = 0; setpenattr_bool(state, VTERM_ATTR_STRIKE, 0); @@ -325,22 +413,19 @@ INTERNAL void vterm_state_setpen(VTermState *state, const long args[], int argco 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); + argi += 1 + lookup_colour(state, CSI_ARG(args[argi+1]), args+argi+2, argcount-argi-2, &state->pen.fg); 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; @@ -348,20 +433,17 @@ INTERNAL void vterm_state_setpen(VTermState *state, const long args[], int argco 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); + argi += 1 + lookup_colour(state, CSI_ARG(args[argi+1]), args+argi+2, argcount-argi-2, &state->pen.bg); 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; @@ -369,14 +451,12 @@ INTERNAL void vterm_state_setpen(VTermState *state, const long args[], int argco 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; @@ -385,16 +465,49 @@ INTERNAL void vterm_state_setpen(VTermState *state, const long args[], int argco break; } - if (!done) + if(!done) { DEBUG_LOG1("libvterm: Unhandled CSI SGR %ld\n", arg); } - while (CSI_ARG_HAS_MORE(args[argi++])) + while(CSI_ARG_HAS_MORE(args[argi++])) ; } } +static int vterm_state_getpen_color(const VTermColor *col, int argi, long args[], int fg) +{ + /* Do nothing if the given color is the default color */ + if (( fg && VTERM_COLOR_IS_DEFAULT_FG(col)) || + (!fg && VTERM_COLOR_IS_DEFAULT_BG(col))) { + return argi; + } + + /* Decide whether to send an indexed color or an RGB color */ + if (VTERM_COLOR_IS_INDEXED(col)) { + const uint8_t idx = col->index; + if (idx < 8) { + args[argi++] = (idx + (fg ? 30 : 40)); + } + else if (idx < 16) { + args[argi++] = (idx - 8 + (fg ? 90 : 100)); + } + else { + args[argi++] = CSI_ARG_FLAG_MORE | (fg ? 38 : 48); + args[argi++] = CSI_ARG_FLAG_MORE | 5; + args[argi++] = idx; + } + } + else if (VTERM_COLOR_IS_RGB(col)) { + args[argi++] = CSI_ARG_FLAG_MORE | (fg ? 38 : 48); + args[argi++] = CSI_ARG_FLAG_MORE | 2; + args[argi++] = CSI_ARG_FLAG_MORE | col->red; + args[argi++] = CSI_ARG_FLAG_MORE | col->green; + args[argi++] = col->blue; + } + return argi; +} + INTERNAL int vterm_state_getpen(VTermState *state, long args[], int argcount UNUSED) { int argi = 0; @@ -405,8 +518,10 @@ INTERNAL int vterm_state_getpen(VTermState *state, long args[], int argcount UNU if(state->pen.italic) args[argi++] = 3; - if(state->pen.underline == 1) + if(state->pen.underline == VTERM_UNDERLINE_SINGLE) args[argi++] = 4; + if(state->pen.underline == VTERM_UNDERLINE_CURLY) + args[argi++] = 4 | CSI_ARG_FLAG_MORE, args[argi++] = 3; if(state->pen.blink) args[argi++] = 5; @@ -414,58 +529,21 @@ INTERNAL int vterm_state_getpen(VTermState *state, long args[], int argcount UNU if(state->pen.reverse) args[argi++] = 7; + if(state->pen.conceal) + args[argi++] = 8; + if(state->pen.strike) args[argi++] = 9; if(state->pen.font) args[argi++] = 10 + state->pen.font; - if(state->pen.underline == 2) + if(state->pen.underline == VTERM_UNDERLINE_DOUBLE) 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; - } - } + argi = vterm_state_getpen_color(&state->pen.fg, argi, args, TRUE); - 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; - } - } + argi = vterm_state_getpen_color(&state->pen.bg, argi, args, FALSE); return argi; } @@ -493,6 +571,10 @@ int vterm_state_get_penattr(const VTermState *state, VTermAttr attr, VTermValue val->boolean = state->pen.reverse; return 1; + case VTERM_ATTR_CONCEAL: + val->boolean = state->pen.conceal; + return 1; + case VTERM_ATTR_STRIKE: val->boolean = state->pen.strike; return 1; diff --git a/src/libvterm/src/rect.h b/src/libvterm/src/rect.h index 3c070e1cd5..2114f24c1b 100644 --- a/src/libvterm/src/rect.h +++ b/src/libvterm/src/rect.h @@ -5,7 +5,7 @@ #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 +/* 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; @@ -14,19 +14,19 @@ static void rect_expand(VTermRect *dst, VTermRect *src) 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 +/* 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 + /* 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 +/* True if the two rectangles are equal */ static int rect_equal(VTermRect *a, VTermRect *b) { return (a->start_row == b->start_row) && @@ -35,7 +35,7 @@ static int rect_equal(VTermRect *a, VTermRect *b) (a->end_col == b->end_col); } -// True if small is contained entirely within big +/* 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; @@ -45,7 +45,7 @@ static int rect_contains(VTermRect *big, VTermRect *small) return 1; } -// True if the rectangles overlap at all +/* 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) diff --git a/src/libvterm/src/screen.c b/src/libvterm/src/screen.c index bf2383a1c6..3e72e4bbe6 100644 --- a/src/libvterm/src/screen.c +++ b/src/libvterm/src/screen.c @@ -10,10 +10,10 @@ #define UNICODE_SPACE 0x20 #define UNICODE_LINEFEED 0x0a -// State of the pen at some moment in time, also used in a cell +/* State of the pen at some moment in time, also used in a cell */ typedef struct { - // After the bitfield + /* After the bitfield */ VTermColor fg, bg; unsigned int bold : 1; @@ -21,24 +21,23 @@ typedef struct unsigned int italic : 1; unsigned int blink : 1; unsigned int reverse : 1; + unsigned int conceal : 1; unsigned int strike : 1; - unsigned int font : 4; // 0 to 9 + unsigned int font : 4; /* 0 to 9 */ - // Extra state storage that isn't strictly pen-related + /* 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) + 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 +/* 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; @@ -48,7 +47,7 @@ struct VTermScreen void *cbdata; VTermDamageSize damage_merge; - // start_row == -1 => no damage + /* start_row == -1 => no damage */ VTermRect damaged; VTermRect pending_scrollrect; int pending_scroll_downward, pending_scroll_rightward; @@ -57,18 +56,24 @@ struct VTermScreen int cols; int global_reverse; - // Primary and Altscreen. buffers[1] is lazily allocated as needed + /* Primary and Altscreen. buffers[1] is lazily allocated as needed */ ScreenCell *buffers[2]; - // buffer will == buffers[0] or buffers[1], depending on altscreen + /* buffer will == buffers[0] or buffers[1], depending on altscreen */ ScreenCell *buffer; - // buffer for a single screen row used in scrollback storage callbacks + /* buffer for a single screen row used in scrollback storage callbacks */ VTermScreenCell *sb_buffer; ScreenPen pen; }; +static void clearcell(const VTermScreen *screen, ScreenCell *cell) +{ + cell->chars[0] = 0; + cell->pen = screen->pen; +} + static ScreenCell *getcell(const VTermScreen *screen, int row, int col) { if(row < 0 || row >= screen->rows) @@ -80,28 +85,18 @@ static ScreenCell *getcell(const VTermScreen *screen, int row, int col) return screen->buffer + (screen->cols * row) + col; } -static ScreenCell *realloc_buffer(VTermScreen *screen, ScreenCell *buffer, int new_rows, int new_cols) +static ScreenCell *alloc_buffer(VTermScreen *screen, int rows, int cols) { - ScreenCell *new_buffer = vterm_allocator_malloc(screen->vt, sizeof(ScreenCell) * new_rows * new_cols); - int row, col; + ScreenCell *new_buffer = vterm_allocator_malloc(screen->vt, sizeof(ScreenCell) * rows * cols); + int row; + int col; - if (new_buffer == NULL) - return NULL; - 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; - } + for(row = 0; row < rows; row++) { + for(col = 0; col < cols; col++) { + clearcell(screen, &new_buffer[row * cols + col]); } } - vterm_allocator_free(screen->vt, buffer); - return new_buffer; } @@ -111,13 +106,13 @@ static void damagerect(VTermScreen *screen, VTermRect rect) switch(screen->damage_merge) { case VTERM_DAMAGE_CELL: - // Always emit damage event + /* 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 + /* 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); @@ -145,7 +140,7 @@ static void damagerect(VTermScreen *screen, VTermRect rect) case VTERM_DAMAGE_SCREEN: case VTERM_DAMAGE_SCROLL: - // Never emit damage event + /* Never emit damage event */ if(screen->damaged.start_row == -1) screen->damaged = rect; else { @@ -207,21 +202,27 @@ static int putglyph(VTermGlyphInfo *info, VTermPos pos, void *user) return 1; } +static void sb_pushline_from_row(VTermScreen *screen, int row) +{ + VTermPos pos; + pos.row = row; + for(pos.col = 0; pos.col < screen->cols; pos.col++) + vterm_screen_get_cell(screen, pos, screen->sb_buffer + pos.col); + + (screen->callbacks->sb_pushline)(screen->cols, screen->sb_buffer, screen->cbdata); +} + 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); - } + dest.start_row == 0 && dest.start_col == 0 && // starts top-left corner + dest.end_col == screen->cols && // full width + screen->buffer == screen->buffers[BUFIDX_PRIMARY]) { // not altscreen + int row; + for(row = 0; row < src.start_row; row++) + sb_pushline_from_row(screen, row); } { @@ -354,14 +355,15 @@ static int scrollrect(VTermRect rect, int downward, int rightward, void *user) return 1; if(rect_contains(&rect, &screen->damaged)) { - // Scroll region entirely contains the damage; just move it + /* 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. + /* 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) { @@ -420,6 +422,9 @@ static int setpenattr(VTermAttr attr, VTermValue *val, void *user) case VTERM_ATTR_REVERSE: screen->pen.reverse = val->boolean; return 1; + case VTERM_ATTR_CONCEAL: + screen->pen.conceal = val->boolean; + return 1; case VTERM_ATTR_STRIKE: screen->pen.strike = val->boolean; return 1; @@ -446,12 +451,13 @@ static int settermprop(VTermProp prop, VTermValue *val, void *user) switch(prop) { case VTERM_PROP_ALTSCREEN: - if(val->boolean && !screen->buffers[1]) + if(val->boolean && !screen->buffers[BUFIDX_ALTSCREEN]) 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 + screen->buffer = val->boolean ? screen->buffers[BUFIDX_ALTSCREEN] : screen->buffers[BUFIDX_PRIMARY]; + /* 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; @@ -460,7 +466,7 @@ static int settermprop(VTermProp prop, VTermValue *val, void *user) damagescreen(screen); break; default: - ; // ignore + ; /* ignore */ } if(screen->callbacks && screen->callbacks->settermprop) @@ -479,95 +485,144 @@ static int bell(void *user) return 0; } -static int resize(int new_rows, int new_cols, VTermPos *delta, void *user) +static void resize_buffer(VTermScreen *screen, int bufidx, int new_rows, int new_cols, int active, VTermStateFields *statefields) { - 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; + ScreenCell *old_buffer = screen->buffers[bufidx]; + ScreenCell *new_buffer = vterm_allocator_malloc(screen->vt, sizeof(ScreenCell) * new_rows * new_cols); - 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); + // Find the final row of old buffer content + int old_row = old_rows - 1; + int new_row = new_rows - 1; + int col; - delta->row -= first_blank_row - new_rows; + while(new_row >= 0 && old_row >= 0) { + for(col = 0; col < old_cols && col < new_cols; col++) + new_buffer[new_row * new_cols + col] = old_buffer[old_row * old_cols + col]; + for( ; col < new_cols; col++) + clearcell(screen, &new_buffer[new_row * new_cols + col]); + + old_row--; + new_row--; + + if(new_row < 0 && old_row >= 0 && + new_buffer[(new_rows - 1) * new_cols].chars[0] == 0 && + (!active || statefields->pos.row < (new_rows - 1))) { + int moverows = new_rows - 1; + memmove(&new_buffer[1 * new_cols], &new_buffer[0], moverows * new_cols * sizeof(ScreenCell)); + + new_row++; } } - 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); + if(old_row >= 0 && bufidx == BUFIDX_PRIMARY) { + /* Push spare lines to scrollback buffer */ + int row; + for(row = 0; row <= old_row; row++) + sb_pushline_from_row(screen, row); + if(active) + statefields->pos.row -= (old_row + 1); + } + if(new_row >= 0 && bufidx == BUFIDX_PRIMARY && + screen->callbacks && screen->callbacks->sb_popline) { + /* Try to backfill rows by popping scrollback buffer */ + while(new_row >= 0) { + VTermPos pos; + if(!(screen->callbacks->sb_popline(old_cols, screen->sb_buffer, screen->cbdata))) + break; - screen->buffer = is_altscreen ? screen->buffers[1] : screen->buffers[0]; + pos.row = new_row; + for(pos.col = 0; pos.col < old_cols && pos.col < new_cols; pos.col += screen->sb_buffer[pos.col].width) { + VTermScreenCell *src = &screen->sb_buffer[pos.col]; + ScreenCell *dst = &new_buffer[pos.row * new_cols + pos.col]; + int i; + + for(i = 0; i < VTERM_MAX_CHARS_PER_CELL; i++) { + dst->chars[i] = src->chars[i]; + if(!src->chars[i]) + break; + } + + dst->pen.bold = src->attrs.bold; + dst->pen.underline = src->attrs.underline; + dst->pen.italic = src->attrs.italic; + dst->pen.blink = src->attrs.blink; + dst->pen.reverse = src->attrs.reverse ^ screen->global_reverse; + dst->pen.conceal = src->attrs.conceal; + dst->pen.strike = src->attrs.strike; + dst->pen.font = src->attrs.font; + + dst->pen.fg = src->fg; + dst->pen.bg = src->bg; + + if(src->width == 2 && pos.col < (new_cols-1)) + (dst + 1)->chars[0] = (uint32_t) -1; + } + for( ; pos.col < new_cols; pos.col++) + clearcell(screen, &new_buffer[pos.row * new_cols + pos.col]); + new_row--; + + if(active) + statefields->pos.row++; + } + } + + if(new_row >= 0) { + /* Scroll new rows back up to the top and fill in blanks at the bottom */ + int moverows = new_rows - new_row - 1; + memmove(&new_buffer[0], &new_buffer[(new_row + 1) * new_cols], moverows * new_cols * sizeof(ScreenCell)); + + for(new_row = moverows; new_row < new_rows; new_row++) + for(col = 0; col < new_cols; col++) + clearcell(screen, &new_buffer[new_row * new_cols + col]); + } + + vterm_allocator_free(screen->vt, old_buffer); + screen->buffers[bufidx] = new_buffer; + + return; + + /* REFLOW TODO: + * Handle delta. Probably needs to be a full cursorpos that we edit + */ +} + +static int resize(int new_rows, int new_cols, VTermStateFields *fields, void *user) +{ + VTermScreen *screen = user; + + int altscreen_active = (screen->buffers[BUFIDX_ALTSCREEN] && screen->buffer == screen->buffers[BUFIDX_ALTSCREEN]); + + int old_cols = screen->cols; + + if(new_cols > old_cols) { + /* Ensure that ->sb_buffer is large enough for a new or and old row */ + if(screen->sb_buffer) + vterm_allocator_free(screen->vt, screen->sb_buffer); + + screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * new_cols); + } + + resize_buffer(screen, 0, new_rows, new_cols, !altscreen_active, fields); + if(screen->buffers[BUFIDX_ALTSCREEN]) + resize_buffer(screen, 1, new_rows, new_cols, altscreen_active, fields); + + screen->buffer = altscreen_active ? screen->buffers[BUFIDX_ALTSCREEN] : screen->buffers[BUFIDX_PRIMARY]; screen->rows = new_rows; screen->cols = new_cols; - vterm_allocator_free(screen->vt, screen->sb_buffer); + if(new_cols <= old_cols) { + if(screen->sb_buffer) + 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); + screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * new_cols); } - 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); - } - } + /* TODO: Maaaaybe we can optimise this if there's no reflow happening */ + damagescreen(screen); if(screen->callbacks && screen->callbacks->resize) return (*screen->callbacks->resize)(new_rows, new_cols, screen->cbdata); @@ -651,8 +706,10 @@ static VTermScreen *screen_new(VTerm *vt) screen->callbacks = NULL; screen->cbdata = NULL; - screen->buffers[0] = realloc_buffer(screen, NULL, rows, cols); - screen->buffer = screen->buffers[0]; + screen->buffers[BUFIDX_PRIMARY] = alloc_buffer(screen, rows, cols); + + screen->buffer = screen->buffers[BUFIDX_PRIMARY]; + screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * cols); if (screen->buffer == NULL || screen->sb_buffer == NULL) { @@ -667,9 +724,12 @@ static VTermScreen *screen_new(VTerm *vt) 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->buffers[BUFIDX_PRIMARY]); + if(screen->buffers[BUFIDX_ALTSCREEN]) + vterm_allocator_free(screen->vt, screen->buffers[BUFIDX_ALTSCREEN]); + vterm_allocator_free(screen->vt, screen->sb_buffer); + vterm_allocator_free(screen->vt, screen); } @@ -743,7 +803,7 @@ size_t vterm_screen_get_text(const VTermScreen *screen, char *str, size_t len, c return _get_chars(screen, 1, str, len, rect); } -// Copy internal to external representation of a screen cell +/* 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); @@ -752,7 +812,7 @@ int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCe if(!intcell) return 0; - for(i = 0; ; i++) { + for(i = 0; i < VTERM_MAX_CHARS_PER_CELL; i++) { cell->chars[i] = intcell->chars[i]; if(!intcell->chars[i]) break; @@ -763,6 +823,7 @@ int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCe cell->attrs.italic = intcell->pen.italic; cell->attrs.blink = intcell->pen.blink; cell->attrs.reverse = intcell->pen.reverse ^ screen->global_reverse; + cell->attrs.conceal = intcell->pen.conceal; cell->attrs.strike = intcell->pen.strike; cell->attrs.font = intcell->pen.font; @@ -798,44 +859,9 @@ int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCe 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 + /* 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) @@ -854,12 +880,11 @@ VTermScreen *vterm_obtain_screen(VTerm *vt) void vterm_screen_enable_altscreen(VTermScreen *screen, int altscreen) { - - if(!screen->buffers[1] && altscreen) { + if(!screen->buffers[BUFIDX_ALTSCREEN] && altscreen) { int rows, cols; vterm_get_size(screen->vt, &rows, &cols); - screen->buffers[1] = realloc_buffer(screen, NULL, rows, cols); + screen->buffers[BUFIDX_ALTSCREEN] = alloc_buffer(screen, rows, cols); } } @@ -874,7 +899,7 @@ void *vterm_screen_get_cbdata(VTermScreen *screen) return screen->cbdata; } -void vterm_screen_set_unrecognised_fallbacks(VTermScreen *screen, const VTermParserCallbacks *fallbacks, void *user) +void vterm_screen_set_unrecognised_fallbacks(VTermScreen *screen, const VTermStateFallbacks *fallbacks, void *user) { vterm_state_set_unrecognised_fallbacks(screen->state, fallbacks, user); } @@ -919,13 +944,15 @@ static int attrs_differ(VTermAttrMask attrs, ScreenCell *a, ScreenCell *b) return 1; if((attrs & VTERM_ATTR_REVERSE_MASK) && (a->pen.reverse != b->pen.reverse)) return 1; + if((attrs & VTERM_ATTR_CONCEAL_MASK) && (a->pen.conceal != b->pen.conceal)) + 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)) + if((attrs & VTERM_ATTR_FOREGROUND_MASK) && !vterm_color_is_equal(&a->pen.fg, &b->pen.fg)) return 1; - if((attrs & VTERM_ATTR_BACKGROUND_MASK) && !vterm_color_equal(a->pen.bg, b->pen.bg)) + if((attrs & VTERM_ATTR_BACKGROUND_MASK) && !vterm_color_is_equal(&a->pen.bg, &b->pen.bg)) return 1; return 0; @@ -958,3 +985,8 @@ int vterm_screen_get_attrs_extent(const VTermScreen *screen, VTermRect *extent, return 1; } + +void vterm_screen_convert_color_to_rgb(const VTermScreen *screen, VTermColor *col) +{ + vterm_state_convert_color_to_rgb(screen->state, col); +} diff --git a/src/libvterm/src/state.c b/src/libvterm/src/state.c index 6b2583af99..a621822333 100644 --- a/src/libvterm/src/state.c +++ b/src/libvterm/src/state.c @@ -11,7 +11,7 @@ static int on_resize(int rows, int cols, void *user); -// Some convenient wrappers to make callback functions easier +/* Some convenient wrappers to make callback functions easier */ static void putglyph(VTermState *state, const uint32_t chars[], int width, VTermPos pos) { @@ -44,6 +44,15 @@ static void updatecursor(VTermState *state, VTermPos *oldpos, int cancel_phantom static void erase(VTermState *state, VTermRect rect, int selective) { + if(rect.end_col == state->cols) { + int row; + /* If we're erasing the final cells of any lines, cancel the continuation + * marker on the subsequent line + */ + for(row = rect.start_row + 1; row < rect.end_row + 1 && row < state->rows; row++) + state->lineinfo[row].continuation = 0; + } + if(state->callbacks && state->callbacks->erase) if((*state->callbacks->erase)(rect, selective, state->cbdata)) return; @@ -73,13 +82,29 @@ static VTermState *vterm_state_new(VTerm *vt) state->bold_is_highbright = 0; + 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->lineinfos[BUFIDX_PRIMARY] = vterm_allocator_malloc(state->vt, state->rows * sizeof(VTermLineInfo)); + /* TODO: Make an 'enable' function */ + state->lineinfos[BUFIDX_ALTSCREEN] = vterm_allocator_malloc(state->vt, state->rows * sizeof(VTermLineInfo)); + state->lineinfo = state->lineinfos[BUFIDX_PRIMARY]; + + state->encoding_utf8.enc = vterm_lookup_encoding(ENC_UTF8, 'u'); + if(state->encoding_utf8.enc->init) + (*state->encoding_utf8.enc->init)(state->encoding_utf8.enc, state->encoding_utf8.data); + 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->lineinfos[BUFIDX_PRIMARY]); + if(state->lineinfos[BUFIDX_ALTSCREEN]) + vterm_allocator_free(state->vt, state->lineinfos[BUFIDX_ALTSCREEN]); vterm_allocator_free(state->vt, state->combine_chars); vterm_allocator_free(state->vt, state); } @@ -106,15 +131,23 @@ static void scroll(VTermState *state, VTermRect rect, int downward, int rightwar // 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); + int row; + VTermLineInfo zeroLineInfo = { 0 }; - if(downward > 0) + if(downward > 0) { memmove(state->lineinfo + rect.start_row, state->lineinfo + rect.start_row + downward, height * sizeof(state->lineinfo[0])); - else + for(row = rect.end_row - downward; row < rect.end_row; row++) + state->lineinfo[row] = zeroLineInfo; + } + else { memmove(state->lineinfo + rect.start_row - downward, state->lineinfo + rect.start_row, height * sizeof(state->lineinfo[0])); + for(row = rect.start_row; row < rect.start_row - downward; row++) + state->lineinfo[row] = zeroLineInfo; + } } if(state->callbacks && state->callbacks->scrollrect) @@ -266,8 +299,9 @@ static int on_text(const char bytes[], size_t len, void *user) 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 + /* 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); @@ -277,10 +311,10 @@ static int on_text(const char bytes[], size_t len, void *user) if(state->gsingle_set && npoints) state->gsingle_set = 0; - // This is a combining char. that needs to be merged with the previous - // glyph output + /* 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 + /* 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; @@ -290,12 +324,12 @@ static int on_text(const char bytes[], size_t len, void *user) printf("} + {"); #endif - // Find where we need to append these combining chars + /* Find where we need to append these combining chars */ int saved_i = 0; while(state->combine_chars[saved_i]) saved_i++; - // Add extra ones + /* Add extra ones */ while(i < npoints && vterm_unicode_is_combining(codepoints[i])) { if(saved_i >= (int)state->combine_chars_size) grow_combine_buffer(state); @@ -311,7 +345,7 @@ static int on_text(const char bytes[], size_t len, void *user) printf("}\n"); #endif - // Now render it + /* Now render it */ putglyph(state, state->combine_chars, state->combine_width, state->combine_pos); } else { @@ -367,6 +401,7 @@ static int on_text(const char bytes[], size_t len, void *user) linefeed(state); state->pos.col = 0; state->at_phantom = 0; + state->lineinfo[state->pos.row].continuation = 1; } if(state->mode.insert) { @@ -384,8 +419,8 @@ static int on_text(const char bytes[], size_t len, void *user) 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 + /* 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) @@ -548,19 +583,12 @@ static int settermprop_int(VTermState *state, VTermProp prop, int v) return vterm_state_set_termprop(state, prop, &val); } -static int settermprop_string(VTermState *state, VTermProp prop, const char *str, size_t len) +static int settermprop_string(VTermState *state, VTermProp prop, VTermStringFragment frag) { - 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; + val.string = frag; + return vterm_state_set_termprop(state, prop, &val); } static void savecursor(VTermState *state, int save) @@ -592,8 +620,9 @@ 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 + /* Easier to decode this from the first byte, even though the final + * byte terminates it + */ switch(bytes[0]) { case ' ': if(len != 2) @@ -922,6 +951,7 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha VTermState *state = user; int leader_byte = 0; int intermed_byte = 0; + int cancel_phantom = 1; VTermPos oldpos = state->pos; int handled = 1; @@ -1237,6 +1267,24 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha state->at_phantom = 0; break; + case 0x62: { // REP - ECMA-48 8.3.103 + const int row_width = THISROWWIDTH(state); + count = CSI_ARG_COUNT(args[0]); + col = state->pos.col + count; + UBOUND(col, row_width); + while (state->pos.col < col) { + putglyph(state, state->combine_chars, state->combine_width, state->pos); + state->pos.col += state->combine_width; + } + if (state->pos.col + state->combine_width >= row_width) { + if (state->mode.autowrap) { + state->at_phantom = 1; + cancel_phantom = 0; + } + } + break; + } + case 0x63: // DA - ECMA-48 8.3.24 val = CSI_ARG_OR(args[0], 0); if(val == 0) @@ -1292,7 +1340,7 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha case 2: case 4: break; - // TODO: 1, 2 and 4 aren't meaningful yet without line tab stops + /* TODO: 1, 2 and 4 aren't meaningful yet without line tab stops */ default: return 0; } @@ -1432,6 +1480,14 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha state->scrollregion_bottom = -1; } + // Setting the scrolling region restores the cursor to the home position + state->pos.row = 0; + state->pos.col = 0; + if(state->mode.origin) { + state->pos.row += state->scrollregion_top; + state->pos.col += SCROLLREGION_LEFT(state); + } + break; case 0x73: // DECSLRM - DEC custom @@ -1453,6 +1509,14 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha state->scrollregion_right = -1; } + // Setting the scrolling region restores the cursor to the home position + state->pos.row = 0; + state->pos.col = 0; + if(state->mode.origin) { + state->pos.row += state->scrollregion_top; + state->pos.col += SCROLLREGION_LEFT(state); + } + break; case 0x74: @@ -1523,7 +1587,7 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha UBOUND(state->pos.col, THISROWWIDTH(state)-1); } - updatecursor(state, &oldpos, 1); + updatecursor(state, &oldpos, cancel_phantom); #ifdef DEBUG if(state->pos.row < 0 || state->pos.row >= state->rows || @@ -1549,83 +1613,119 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha return 1; } -static int on_osc(const char *command, size_t cmdlen, void *user) +static int on_osc(int command, VTermStringFragment frag, 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: ]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: ]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)) + switch(command) { + case 0: + settermprop_string(state, VTERM_PROP_ICONNAME, frag); + settermprop_string(state, VTERM_PROP_TITLE, frag); return 1; + case 1: + settermprop_string(state, VTERM_PROP_ICONNAME, frag); + return 1; + + case 2: + settermprop_string(state, VTERM_PROP_TITLE, frag); + return 1; + + case 10: + { + // request foreground color: ]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; + } + + case 11: + { + // request background color: ]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; + } + case 12: + settermprop_string(state, VTERM_PROP_CURSORCOLOR, frag); + return 1; + + default: + if(state->fallbacks && state->fallbacks->osc) + if((*state->fallbacks->osc)(command, frag, state->fbdata)) + return 1; + } + return 0; } -static void request_status_string(VTermState *state, const char *command, size_t cmdlen) +static void request_status_string(VTermState *state, VTermStringFragment frag) { - 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, ""); - } + VTerm *vt = state->vt; + + char *tmp = state->tmp.decrqss; + size_t i = 0; + + if(frag.initial) + tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0; + + while(i < sizeof(state->tmp.decrqss)-1 && tmp[i]) + i++; + while(i < sizeof(state->tmp.decrqss)-1 && frag.len--) + tmp[i++] = (frag.str++)[0]; + tmp[i] = 0; + + if(!frag.final) + return; + + switch(tmp[0] | tmp[1]<<8 | tmp[2]<<16) { + case 'm': { + // Query SGR + long args[20]; + int argc = vterm_state_getpen(state, args, sizeof(args)/sizeof(args[0])); + size_t cur = 0; + int argi; + + cur += SNPRINTF(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur, + vt->mode.ctrl8bit ? "\x90" "1$r" : ESC_S "P" "1$r"); // DCS 1$r ... + if(cur >= vt->tmpbuffer_len) 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)); + + for(argi = 0; argi < argc; argi++) { + cur += SNPRINTF(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur, + argi == argc - 1 ? "%ld" : + CSI_ARG_HAS_MORE(args[argi]) ? "%ld:" : + "%ld;", + CSI_ARG(args[argi])); + if(cur >= vt->tmpbuffer_len) + return; + } + + cur += SNPRINTF(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur, + vt->mode.ctrl8bit ? "m" "\x9C" : "m" ESC_S "\\"); // ... m ST + if(cur >= vt->tmpbuffer_len) return; + + vterm_push_output_bytes(vt, vt->tmpbuffer, cur); + return; } - if(cmdlen == 2) { - if(strneq(command, " q", 2)) { + case 'r': + // Query DECSTBM + vterm_push_output_sprintf_dcs(vt, "1$r%d;%dr", state->scrollregion_top+1, SCROLLREGION_BOTTOM(state)); + return; + + case 's': + // Query DECSLRM + vterm_push_output_sprintf_dcs(vt, "1$r%d;%ds", SCROLLREGION_LEFT(state)+1, SCROLLREGION_RIGHT(state)); + return; + + case ' '|('q'<<8): { + // Query DECSCUSR int reply; switch(state->mode.cursor_shape) { case VTERM_PROP_CURSORSHAPE_BLOCK: reply = 2; break; @@ -1634,30 +1734,32 @@ static void request_status_string(VTermState *state, const char *command, size_t } if(state->mode.cursor_blink) reply--; - vterm_push_output_sprintf_dcs(state->vt, "1$r%d q", reply); + vterm_push_output_sprintf_dcs(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); + + case '\"'|('q'<<8): + // Query DECSCA + vterm_push_output_sprintf_dcs(vt, "1$r%d\"q", state->protected_cell ? 1 : 2); return; - } } - vterm_push_output_sprintf_dcs(state->vt, "0$r%.s", (int)cmdlen, command); + vterm_push_output_sprintf_dcs(state->vt, "0$r%s", tmp); } -static int on_dcs(const char *command, size_t cmdlen, void *user) +static int on_dcs(const char *command, size_t commandlen, VTermStringFragment frag, void *user) { VTermState *state = user; - if(cmdlen >= 2 && strneq(command, "$q", 2)) { - request_status_string(state, command+2, cmdlen-2); + if(commandlen == 2 && strneq(command, "$q", 2)) { + request_status_string(state, frag); return 1; } else if(state->fallbacks && state->fallbacks->dcs) - if((*state->fallbacks->dcs)(command, cmdlen, state->fbdata)) + if((*state->fallbacks->dcs)(command, commandlen, frag, state->fbdata)) return 1; + DEBUG_LOG2("libvterm: Unhandled DCS %.*s\n", (int)commandlen, command); return 0; } @@ -1665,7 +1767,7 @@ static int on_resize(int rows, int cols, void *user) { VTermState *state = user; VTermPos oldpos = state->pos; - VTermPos delta = { 0, 0 }; + VTermStateFields fields; if(cols != state->cols) { int col; @@ -1673,7 +1775,7 @@ static int on_resize(int rows, int cols, void *user) if (newtabstops == NULL) return 0; - // TODO: This can all be done much more efficiently bytewise + /* TODO: This can all be done much more efficiently bytewise */ for(col = 0; col < state->cols && col < cols; col++) { unsigned char mask = 1 << (col & 7); if(state->tabstops[col >> 3] & mask) @@ -1695,22 +1797,30 @@ static int on_resize(int rows, int cols, void *user) } if(rows != state->rows) { - int row; - VTermLineInfo *newlineinfo = vterm_allocator_malloc(state->vt, rows * sizeof(VTermLineInfo)); - if (newlineinfo == NULL) - return 0; + int bufidx; + for(bufidx = BUFIDX_PRIMARY; bufidx <= BUFIDX_ALTSCREEN; bufidx++) { + int row; + VTermLineInfo *oldlineinfo = state->lineinfos[bufidx]; + VTermLineInfo *newlineinfo; + if(!oldlineinfo) + continue; - for(row = 0; row < state->rows && row < rows; row++) { - newlineinfo[row] = state->lineinfo[row]; + newlineinfo = vterm_allocator_malloc(state->vt, rows * sizeof(VTermLineInfo)); + + for(row = 0; row < state->rows && row < rows; row++) { + newlineinfo[row] = oldlineinfo[row]; + } + + for( ; row < rows; row++) { + VTermLineInfo lineInfo = {0}; + newlineinfo[row] = lineInfo; + } + + vterm_allocator_free(state->vt, state->lineinfos[bufidx]); + state->lineinfos[bufidx] = newlineinfo; } - for( ; row < rows; row++) { - newlineinfo[row].doublewidth = 0; - newlineinfo[row].doubleheight = 0; - } - - vterm_allocator_free(state->vt, state->lineinfo); - state->lineinfo = newlineinfo; + state->lineinfo = state->lineinfos[state->mode.alt_screen ? BUFIDX_ALTSCREEN : BUFIDX_PRIMARY]; } state->rows = rows; @@ -1721,17 +1831,18 @@ static int on_resize(int rows, int cols, void *user) if(state->scrollregion_right > -1) UBOUND(state->scrollregion_right, state->cols); + fields.pos = state->pos; + if(state->callbacks && state->callbacks->resize) - (*state->callbacks->resize)(rows, cols, &delta, state->cbdata); + (*state->callbacks->resize)(rows, cols, &fields, state->cbdata); + + state->pos = fields.pos; 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) @@ -1767,17 +1878,6 @@ VTermState *vterm_obtain_state(VTerm *vt) 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; @@ -1895,7 +1995,7 @@ void *vterm_state_get_cbdata(VTermState *state) return state->cbdata; } -void vterm_state_set_unrecognised_fallbacks(VTermState *state, const VTermParserCallbacks *fallbacks, void *user) +void vterm_state_set_unrecognised_fallbacks(VTermState *state, const VTermStateFallbacks *fallbacks, void *user) { if(fallbacks) { state->fallbacks = fallbacks; @@ -1914,8 +2014,8 @@ void *vterm_state_get_unrecognised_fbdata(VTermState *state) 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 + /* 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; @@ -1940,6 +2040,7 @@ int vterm_state_set_termprop(VTermState *state, VTermProp prop, VTermValue *val) return 1; case VTERM_PROP_ALTSCREEN: state->mode.alt_screen = val->boolean; + state->lineinfo = state->lineinfos[state->mode.alt_screen ? BUFIDX_ALTSCREEN : BUFIDX_PRIMARY]; if(state->mode.alt_screen) { VTermRect rect = {0, 0, 0, 0}; rect.end_row = state->rows; diff --git a/src/libvterm/src/unicode.c b/src/libvterm/src/unicode.c index 424b3e206e..651e5552c6 100644 --- a/src/libvterm/src/unicode.c +++ b/src/libvterm/src/unicode.c @@ -1,11 +1,10 @@ #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 - * ################################################################### - */ +// ### 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 @@ -75,8 +74,8 @@ struct interval { #if !defined(WCWIDTH_FUNCTION) || !defined(IS_COMBINING_FUNCTION) -// sorted list of non-overlapping intervals of non-spacing characters -// generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" +/* sorted list of non-overlapping intervals of non-spacing characters */ +/* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */ // Replaced by the combining table from Vim. static const struct interval combining[] = { {0X0300, 0X036F}, @@ -362,7 +361,7 @@ static const struct interval combining[] = { }; #endif -// auxiliary function for binary search in interval table +/* 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; @@ -382,6 +381,7 @@ static int bisearch(uint32_t ucs, const struct interval *table, int max) { return 0; } + /* The following two functions define the column width of an ISO 10646 * character as follows: * @@ -422,30 +422,30 @@ int WCWIDTH_FUNCTION(uint32_t ucs); static int mk_wcwidth(uint32_t ucs) { - // test for 8-bit control characters + /* 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 + /* 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 + /* if we arrive here, ucs is not a combining or C0/C1 control character */ - return 1 + + return 1 + (ucs >= 0x1100 && - (ucs <= 0x115f || // Hangul Jamo init. consonants + (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 != 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))); @@ -479,8 +479,8 @@ static int mk_wcswidth(const uint32_t *pwcs, size_t n) static int mk_wcwidth_cjk(uint32_t ucs) { #endif - // sorted list of non-overlapping intervals of East Asian Ambiguous - // characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" + /* 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 }, @@ -537,7 +537,7 @@ static int mk_wcwidth_cjk(uint32_t ucs) }; #if 0 - // binary search in table of non-spacing characters + /* binary search in table of non-spacing characters */ if (bisearch(ucs, ambiguous, sizeof(ambiguous) / sizeof(struct interval) - 1)) return 2; @@ -545,6 +545,7 @@ static int mk_wcwidth_cjk(uint32_t ucs) return mk_wcwidth(ucs); } + static int mk_wcswidth_cjk(const uint32_t *pwcs, size_t n) { int w, width = 0; @@ -591,8 +592,15 @@ vterm_get_special_pty_type_placeholder(void) // ################################ // ### The rest added by Paul Evans +static const struct interval fullwidth[] = { +#include "fullwidth.inc" +}; + INTERNAL int vterm_unicode_width(uint32_t codepoint) { + if(bisearch(codepoint, fullwidth, sizeof(fullwidth) / sizeof(fullwidth[0]) - 1)) + return 2; + return WCWIDTH_FUNCTION(codepoint); } diff --git a/src/libvterm/src/utf8.h b/src/libvterm/src/utf8.h index d2538d5f82..886a1ca5a6 100644 --- a/src/libvterm/src/utf8.h +++ b/src/libvterm/src/utf8.h @@ -16,7 +16,7 @@ INLINE unsigned int utf8_seqlen(long codepoint) } #endif -// Does NOT NUL-terminate the buffer +/* Does NOT NUL-terminate the buffer */ int fill_utf8(long codepoint, char *str); #if defined(DEFINE_INLINES) || USE_INLINE @@ -44,4 +44,4 @@ INLINE int fill_utf8(long codepoint, char *str) return nbytes; } #endif -// end copy +/* end copy */ diff --git a/src/libvterm/src/vterm.c b/src/libvterm/src/vterm.c index 1d6a977f1b..0211ea1479 100644 --- a/src/libvterm/src/vterm.c +++ b/src/libvterm/src/vterm.c @@ -10,9 +10,9 @@ #include "utf8.h" -/////////////////// -// API functions // -/////////////////// +/***************** + * API functions * + *****************/ static void *default_malloc(size_t size, void *allocdata UNUSED) { @@ -39,7 +39,7 @@ VTerm *vterm_new(int rows, int cols) VTerm *vterm_new_with_allocator(int rows, int cols, VTermAllocatorFunctions *funcs, void *allocdata) { - // Need to bootstrap using the allocator function directly + /* Need to bootstrap using the allocator function directly */ VTerm *vt = (*funcs->malloc)(sizeof(VTerm), allocdata); if (vt == NULL) @@ -55,21 +55,22 @@ VTerm *vterm_new_with_allocator(int rows, int cols, VTermAllocatorFunctions *fun 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->outfunc = NULL; + vt->outdata = NULL; vt->outbuffer_len = 200; vt->outbuffer_cur = 0; vt->outbuffer = vterm_allocator_malloc(vt, vt->outbuffer_len); - if (vt->outbuffer == NULL) + + vt->tmpbuffer_len = 64; + vt->tmpbuffer = vterm_allocator_malloc(vt, vt->tmpbuffer_len); + + if (vt->tmpbuffer == NULL + || vt->outbuffer == NULL + || vt->tmpbuffer == NULL) { - vterm_allocator_free(vt, vt->parser.strbuffer); + vterm_allocator_free(vt, vt->outbuffer); + vterm_allocator_free(vt, vt->tmpbuffer); vterm_allocator_free(vt, vt); return NULL; } @@ -85,8 +86,8 @@ void vterm_free(VTerm *vt) 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->tmpbuffer); vterm_allocator_free(vt, vt); } @@ -132,70 +133,42 @@ void vterm_set_utf8(VTerm *vt, int is_utf8) vt->mode.utf8 = is_utf8; } +void vterm_output_set_callback(VTerm *vt, VTermOutputCallback *func, void *user) +{ + vt->outfunc = func; + vt->outdata = user; +} + INTERNAL void vterm_push_output_bytes(VTerm *vt, const char *bytes, size_t len) { + if(vt->outfunc) { + (vt->outfunc)(bytes, len, vt->outdata); + return; + } + 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; + DEBUG_LOG("vterm_push_output_bytes(): buffer overflow; dropping output\n"); + return; } 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; + size_t len; #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; + len = VSNPRINTF(vt->tmpbuffer, vt->tmpbuffer_len, format, args); + vterm_push_output_bytes(vt, vt->tmpbuffer, len); #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; - } + len = vsprintf(buffer, format, args); + vterm_push_output_bytes(vt, buffer, len); #endif } @@ -209,40 +182,45 @@ INTERNAL void vterm_push_output_sprintf(VTerm *vt, const char *format, ...) INTERNAL void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, const char *fmt, ...) { - size_t orig_cur = vt->outbuffer_cur; + size_t cur; va_list args; if(ctrl >= 0x80 && !vt->mode.ctrl8bit) - vterm_push_output_sprintf(vt, ESC_S "%c", ctrl - 0x40); + cur = SNPRINTF(vt->tmpbuffer, vt->tmpbuffer_len, + ESC_S "%c", ctrl - 0x40); else - vterm_push_output_sprintf(vt, "%c", ctrl); + cur = SNPRINTF(vt->tmpbuffer, vt->tmpbuffer_len, + "%c", ctrl); + if(cur >= vt->tmpbuffer_len) + return; + vterm_push_output_bytes(vt, vt->tmpbuffer, cur); 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; + size_t 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); + cur = SNPRINTF(vt->tmpbuffer, vt->tmpbuffer_len, + vt->mode.ctrl8bit ? "\x90" : ESC_S "P"); // DCS + + if(cur >= vt->tmpbuffer_len) + return; + vterm_push_output_bytes(vt, vt->tmpbuffer, cur); 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; + cur = SNPRINTF(vt->tmpbuffer, vt->tmpbuffer_len, + vt->mode.ctrl8bit ? "\x9C" : ESC_S "\\"); // ST + if(cur >= vt->tmpbuffer_len) + return; + vterm_push_output_bytes(vt, vt->tmpbuffer, cur); } size_t vterm_output_get_buffer_size(const VTerm *vt) @@ -283,6 +261,7 @@ VTermValueType vterm_get_attr_type(VTermAttr attr) 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_CONCEAL: 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; @@ -290,7 +269,7 @@ VTermValueType vterm_get_attr_type(VTermAttr attr) case VTERM_N_ATTRS: return 0; } - return 0; // UNREACHABLE + return 0; /* UNREACHABLE */ } VTermValueType vterm_get_prop_type(VTermProp prop) @@ -308,7 +287,7 @@ VTermValueType vterm_get_prop_type(VTermProp prop) case VTERM_N_PROPS: return 0; } - return 0; // UNREACHABLE + return 0; /* UNREACHABLE */ } void vterm_scroll_rect(VTermRect rect, @@ -323,24 +302,26 @@ void vterm_scroll_rect(VTermRect rect, 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 + /* Scroll more than area; just erase the lot */ (*eraserect)(rect, 0, user); return; } if(rightward >= 0) { - // rect: [XXX................] - // src: [----------------] - // dest: [----------------] + /* 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: [----------------] + /* rect: [................XXX] + * src: [----------------] + * dest: [----------------] + */ int leftward = -rightward; dest.start_col = rect.start_col + leftward; dest.end_col = rect.end_col; @@ -396,8 +377,7 @@ void vterm_copy_cells(VTermRect dest, test_row = dest.start_row - 1; inc_row = -1; } - else { - // downward >= 0 + else /* downward >= 0 */ { init_row = dest.start_row; test_row = dest.end_row; inc_row = +1; @@ -408,8 +388,7 @@ void vterm_copy_cells(VTermRect dest, test_col = dest.start_col - 1; inc_col = -1; } - else { - // rightward >= 0 + else /* rightward >= 0 */ { init_col = dest.start_col; test_col = dest.end_col; inc_col = +1; @@ -423,3 +402,20 @@ void vterm_copy_cells(VTermRect dest, (*copycell)(pos, srcpos, user); } } + +void vterm_check_version(int major, int minor) +{ + if(major != VTERM_VERSION_MAJOR) { + fprintf(stderr, "libvterm major version mismatch; %d (wants) != %d (library)\n", + major, VTERM_VERSION_MAJOR); + exit(1); + } + + if(minor > VTERM_VERSION_MINOR) { + fprintf(stderr, "libvterm minor version mismatch; %d (wants) > %d (library)\n", + minor, VTERM_VERSION_MINOR); + exit(1); + } + + // Happy +} diff --git a/src/libvterm/src/vterm_internal.h b/src/libvterm/src/vterm_internal.h index e2b8b159be..cc0c64d30a 100644 --- a/src/libvterm/src/vterm_internal.h +++ b/src/libvterm/src/vterm_internal.h @@ -32,6 +32,9 @@ #define CSI_ARGS_MAX 16 #define CSI_LEADER_MAX 16 +#define BUFIDX_PRIMARY 0 +#define BUFIDX_ALTSCREEN 1 + typedef struct VTermEncoding VTermEncoding; typedef struct { @@ -50,19 +53,11 @@ struct VTermPen unsigned int italic:1; unsigned int blink:1; unsigned int reverse:1; + unsigned int conceal:1; unsigned int strike:1; - unsigned int font:4; // To store 0-9 + 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; @@ -70,40 +65,44 @@ struct VTermState const VTermStateCallbacks *callbacks; void *cbdata; - const VTermParserCallbacks *fallbacks; + const VTermStateFallbacks *fallbacks; void *fbdata; int rows; int cols; - // Current cursor position + /* Current cursor position */ VTermPos pos; - int at_phantom; // True if we're on the "81st" phantom column to defer a wraparound + 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 + 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 + 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 + /* Bitvector of tab stops */ unsigned char *tabstops; + /* Primary and Altscreen; lineinfos[1] is lazily allocated as needed */ + VTermLineInfo *lineinfos[2]; + + /* lineinfo will == lineinfos[0] or lineinfos[1], depending on altscreen */ 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 + /* 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 + /* 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 @@ -136,13 +135,11 @@ struct VTermState 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 + /* Saved state under DEC mode 1048/1049 */ struct { VTermPos pos; struct VTermPen pen; @@ -153,15 +150,13 @@ struct VTermState unsigned int cursor_shape:2; } mode; } saved; + + /* Temporary state for DECRQSS parsing */ + union { + char decrqss[4]; + } tmp; }; -typedef enum { - VTERM_PARSER_OSC, - VTERM_PARSER_DCS, - - VTERM_N_PARSER_TYPES -} VTermParserStringType; - struct VTerm { VTermAllocatorFunctions *allocator; @@ -181,36 +176,53 @@ struct VTerm CSI_LEADER, CSI_ARGS, CSI_INTERMED, - ESC, - // below here are the "string states" - STRING, - ESC_IN_STRING, + DCS_COMMAND, + /* below here are the "string states" */ + OSC_COMMAND, + OSC, + DCS, } state; + unsigned int in_esc : 1; + int intermedlen; char intermed[INTERMED_MAX]; - int csi_leaderlen; - char csi_leader[CSI_LEADER_MAX]; + union { + struct { + int leaderlen; + char leader[CSI_LEADER_MAX]; - int csi_argi; - long csi_args[CSI_ARGS_MAX]; + int argi; + long args[CSI_ARGS_MAX]; + } csi; + struct { + int command; + } osc; + struct { + int commandlen; + char command[CSI_LEADER_MAX]; + } dcs; + } v; const VTermParserCallbacks *callbacks; void *cbdata; - VTermParserStringType stringtype; - char *strbuffer; - size_t strbuffer_len; - size_t strbuffer_cur; + int string_initial; } parser; - // len == malloc()ed size; cur == number of valid bytes + /* len == malloc()ed size; cur == number of valid bytes */ + + VTermOutputCallback *outfunc; + void *outdata; char *outbuffer; size_t outbuffer_len; size_t outbuffer_cur; + char *tmpbuffer; + size_t tmpbuffer_len; + VTermState *state; VTermScreen *screen; @@ -265,4 +277,24 @@ int vterm_unicode_is_combining(uint32_t codepoint); int vterm_unicode_is_ambiguous(uint32_t codepoint); int vterm_get_special_pty_type(void); +#if (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 500) \ + || defined(_ISOC99_SOURCE) || defined(_BSD_SOURCE) +# undef VSNPRINTF +# define VSNPRINTF vsnprintf +# undef SNPRINTF +#else +# ifdef VSNPRINTF +// Use a provided vsnprintf() function. +int VSNPRINTF(char *str, size_t str_m, const char *fmt, va_list ap); +# endif +# ifdef SNPRINTF +// Use a provided snprintf() function. +int SNPRINTF(char *str, size_t str_m, const char *fmt, ...); +# endif +#endif +#ifndef SNPRINTF +# define SNPRINTF snprintf +#endif + + #endif diff --git a/src/libvterm/t/02parser.test b/src/libvterm/t/02parser.test index 66d487dad9..0a21b927e6 100644 --- a/src/libvterm/t/02parser.test +++ b/src/libvterm/t/02parser.test @@ -132,15 +132,31 @@ PUSH "\e[12\n;3X" !OSC BEL PUSH "\e]1;Hello\x07" - osc "1;Hello" + osc [1 "Hello"] !OSC ST (7bit) PUSH "\e]1;Hello\e\\" - osc "1;Hello" + osc [1 "Hello"] !OSC ST (8bit) PUSH "\x{9d}1;Hello\x9c" - osc "1;Hello" + osc [1 "Hello"] + +!OSC in parts +PUSH "\e]52;abc" + osc [52 "abc" +PUSH "def" + osc "def" +PUSH "ghi\e\\" + osc "ghi"] + +!OSC BEL without semicolon +PUSH "\e]1234\x07" + osc [1234 ] + +!OSC ST without semicolon +PUSH "\e]1234\e\\" + osc [1234 ] !Escape cancels OSC, starts Escape PUSH "\e]Something\e9" @@ -152,20 +168,21 @@ PUSH "\e]12\x{18}AB" !C0 in OSC interrupts and continues PUSH "\e]2;\nBye\x07" + osc [2 "" control 10 - osc "2;Bye" + osc "Bye"] !DCS BEL PUSH "\ePHello\x07" - dcs "Hello" + dcs ["Hello"] !DCS ST (7bit) PUSH "\ePHello\e\\" - dcs "Hello" + dcs ["Hello"] !DCS ST (8bit) PUSH "\x{90}Hello\x9c" - dcs "Hello" + dcs ["Hello"] !Escape cancels DCS, starts Escape PUSH "\ePSomething\e9" @@ -177,8 +194,9 @@ PUSH "\eP12\x{18}AB" !C0 in OSC interrupts and continues PUSH "\ePBy\ne\x07" + dcs ["By" control 10 - dcs "Bye" + dcs "e"] !NUL ignored PUSH "\x{00}" diff --git a/src/libvterm/t/10state_putglyph.test b/src/libvterm/t/10state_putglyph.test index 6d5d56a38d..bae0423b17 100644 --- a/src/libvterm/t/10state_putglyph.test +++ b/src/libvterm/t/10state_putglyph.test @@ -30,6 +30,13 @@ PUSH "\xEF\xBC\x90 " putglyph 0xff10 2 0,0 putglyph 0x20 1 0,2 +!UTF-8 emoji wide char +# U+1F600 = 0xF0 0x9F 0x98 0x80 name: GRINNING FACE +RESET +PUSH "\xF0\x9F\x98\x80 " + putglyph 0x1f600 2 0,0 + putglyph 0x20 1 0,2 + !UTF-8 combining chars # U+0301 = 0xCC 0x81 name: COMBINING ACUTE RESET diff --git a/src/libvterm/t/12state_scroll.test b/src/libvterm/t/12state_scroll.test index ca305d499b..c1f2791d00 100644 --- a/src/libvterm/t/12state_scroll.test +++ b/src/libvterm/t/12state_scroll.test @@ -40,8 +40,8 @@ PUSH "\n" ?cursor = 20,0 !Index in DECSTBM -PUSH "\e[10H" PUSH "\e[9;10r" +PUSH "\e[10H" PUSH "\eM" ?cursor = 8,0 PUSH "\eM" @@ -148,3 +148,9 @@ PUSH "\e[2T" moverect 0..23,0..80 -> 2..25,0..80 erase 0..2,0..80 ?cursor = 0,0 + +!DECSTBM resets cursor position +PUSH "\e[5;5H" + ?cursor = 4,4 +PUSH "\e[r" + ?cursor = 0,0 diff --git a/src/libvterm/t/18state_termprops.test b/src/libvterm/t/18state_termprops.test index 9e6928a21e..83c333f3fd 100644 --- a/src/libvterm/t/18state_termprops.test +++ b/src/libvterm/t/18state_termprops.test @@ -33,4 +33,10 @@ PUSH "\e[3 q" !Title PUSH "\e]2;Here is my title\a" - settermprop 4 "Here is my title" + settermprop 4 ["Here is my title"] + +!Title split write +PUSH "\e]2;Here is" + settermprop 4 ["Here is" +PUSH " another title\a" + settermprop 4 " another title"] diff --git a/src/libvterm/t/25state_input.test b/src/libvterm/t/25state_input.test index a5119fbd87..4eb4c6abdf 100644 --- a/src/libvterm/t/25state_input.test +++ b/src/libvterm/t/25state_input.test @@ -111,6 +111,18 @@ PUSH "\e[20h" INKEY 0 Enter output "\x0d\x0a" +!Unmodified F1 is SS3 P +INKEY 0 F1 + output "\eOP" + +!Modified F1 is CSI P +INKEY S F1 + output "\e[1;2P" +INKEY A F1 + output "\e[1;3P" +INKEY C F1 + output "\e[1;5P" + !Keypad in DECKPNM INKEY 0 KP0 output "0" diff --git a/src/libvterm/t/26state_query.test b/src/libvterm/t/26state_query.test index 3ace2d5323..c543b92456 100644 --- a/src/libvterm/t/26state_query.test +++ b/src/libvterm/t/26state_query.test @@ -41,10 +41,10 @@ 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 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" @@ -59,4 +59,4 @@ PUSH "\e F" !Truncation on attempted buffer overflow PUSH "\e[6n" x 30 - output "\e[10;10R" x 24 + output "\e[10;10R" x 25 diff --git a/src/libvterm/t/29state_fallback.test b/src/libvterm/t/29state_fallback.test index adf1c233ab..7995dd1b6a 100644 --- a/src/libvterm/t/29state_fallback.test +++ b/src/libvterm/t/29state_fallback.test @@ -12,8 +12,8 @@ PUSH "\e[?15;2z" !Unrecognised OSC PUSH "\e]27;Something\e\\" - osc "27;Something" + osc [27 "Something"] !Unrecognised DCS PUSH "\ePz123\e\\" - dcs "z123" + dcs ["z123"] diff --git a/src/libvterm/t/30pen.test b/src/libvterm/t/30state_pen.test similarity index 66% rename from src/libvterm/t/30pen.test rename to src/libvterm/t/30state_pen.test index 7a671e7530..915baec7cd 100644 --- a/src/libvterm/t/30pen.test +++ b/src/libvterm/t/30state_pen.test @@ -10,8 +10,8 @@ PUSH "\e[m" ?pen blink = off ?pen reverse = off ?pen font = 0 - ?pen foreground = rgb(240,240,240) - ?pen background = rgb(0,0,0) + ?pen foreground = rgb(240,240,240,is_default_fg) + ?pen background = rgb(0,0,0,is_default_bg) !Bold PUSH "\e[1m" @@ -28,6 +28,14 @@ PUSH "\e[21m" ?pen underline = 2 PUSH "\e[24m" ?pen underline = 0 +PUSH "\e[4m\e[4:0m" + ?pen underline = 0 +PUSH "\e[4:1m" + ?pen underline = 1 +PUSH "\e[4:2m" + ?pen underline = 2 +PUSH "\e[4:3m" + ?pen underline = 3 PUSH "\e[4m\e[m" ?pen underline = 0 @@ -67,40 +75,40 @@ PUSH "\e[11m\e[m" !Foreground PUSH "\e[31m" - ?pen foreground = rgb(224,0,0) + ?pen foreground = idx(1) PUSH "\e[32m" - ?pen foreground = rgb(0,224,0) + ?pen foreground = idx(2) PUSH "\e[34m" - ?pen foreground = rgb(0,0,224) + ?pen foreground = idx(4) PUSH "\e[91m" - ?pen foreground = rgb(255,64,64) + ?pen foreground = idx(9) PUSH "\e[38:2:10:20:30m" ?pen foreground = rgb(10,20,30) PUSH "\e[38:5:1m" - ?pen foreground = rgb(224,0,0) + ?pen foreground = idx(1) PUSH "\e[39m" - ?pen foreground = rgb(240,240,240) + ?pen foreground = rgb(240,240,240,is_default_fg) !Background PUSH "\e[41m" - ?pen background = rgb(224,0,0) + ?pen background = idx(1) PUSH "\e[42m" - ?pen background = rgb(0,224,0) + ?pen background = idx(2) PUSH "\e[44m" - ?pen background = rgb(0,0,224) + ?pen background = idx(4) PUSH "\e[101m" - ?pen background = rgb(255,64,64) + ?pen background = idx(9) PUSH "\e[48:2:10:20:30m" ?pen background = rgb(10,20,30) PUSH "\e[48:5:1m" - ?pen background = rgb(224,0,0) + ?pen background = idx(1) PUSH "\e[49m" - ?pen background = rgb(0,0,0) + ?pen background = rgb(0,0,0,is_default_bg) !Bold+ANSI colour == highbright PUSH "\e[m\e[1;37m" ?pen bold = on - ?pen foreground = rgb(255,255,255) + ?pen foreground = idx(15) PUSH "\e[m\e[37;1m" ?pen bold = on - ?pen foreground = rgb(255,255,255) + ?pen foreground = idx(15) diff --git a/src/libvterm/t/31state_rep.test b/src/libvterm/t/31state_rep.test new file mode 100644 index 0000000000..f820e675cf --- /dev/null +++ b/src/libvterm/t/31state_rep.test @@ -0,0 +1,128 @@ +INIT +UTF8 1 +WANTSTATE g + +!REP no argument +RESET +PUSH "a\e[b" + putglyph 0x61 1 0,0 + putglyph 0x61 1 0,1 + +!REP zero (zero should be interpreted as one) +RESET +PUSH "a\e[0b" + putglyph 0x61 1 0,0 + putglyph 0x61 1 0,1 + +!REP lowercase a times two +RESET +PUSH "a\e[2b" + putglyph 0x61 1 0,0 + putglyph 0x61 1 0,1 + putglyph 0x61 1 0,2 + +!REP with UTF-8 1 char +# U+00E9 = 0xC3 0xA9 name: LATIN SMALL LETTER E WITH ACUTE +RESET +PUSH "\xC3\xA9\e[b" + putglyph 0xe9 1 0,0 + putglyph 0xe9 1 0,1 + +!REP with UTF-8 wide char +# U+00E9 = 0xC3 0xA9 name: LATIN SMALL LETTER E WITH ACUTE +RESET +PUSH "\xEF\xBC\x90\e[b" + putglyph 0xff10 2 0,0 + putglyph 0xff10 2 0,2 + +!REP with UTF-8 combining character +RESET +PUSH "e\xCC\x81\e[b" + putglyph 0x65,0x301 1 0,0 + putglyph 0x65,0x301 1 0,1 + +!REP till end of line +RESET +PUSH "a\e[1000bb" + putglyph 0x61 1 0,0 + putglyph 0x61 1 0,1 + putglyph 0x61 1 0,2 + putglyph 0x61 1 0,3 + putglyph 0x61 1 0,4 + putglyph 0x61 1 0,5 + putglyph 0x61 1 0,6 + putglyph 0x61 1 0,7 + putglyph 0x61 1 0,8 + putglyph 0x61 1 0,9 + putglyph 0x61 1 0,10 + putglyph 0x61 1 0,11 + putglyph 0x61 1 0,12 + putglyph 0x61 1 0,13 + putglyph 0x61 1 0,14 + putglyph 0x61 1 0,15 + putglyph 0x61 1 0,16 + putglyph 0x61 1 0,17 + putglyph 0x61 1 0,18 + putglyph 0x61 1 0,19 + putglyph 0x61 1 0,20 + putglyph 0x61 1 0,21 + putglyph 0x61 1 0,22 + putglyph 0x61 1 0,23 + putglyph 0x61 1 0,24 + putglyph 0x61 1 0,25 + putglyph 0x61 1 0,26 + putglyph 0x61 1 0,27 + putglyph 0x61 1 0,28 + putglyph 0x61 1 0,29 + putglyph 0x61 1 0,30 + putglyph 0x61 1 0,31 + putglyph 0x61 1 0,32 + putglyph 0x61 1 0,33 + putglyph 0x61 1 0,34 + putglyph 0x61 1 0,35 + putglyph 0x61 1 0,36 + putglyph 0x61 1 0,37 + putglyph 0x61 1 0,38 + putglyph 0x61 1 0,39 + putglyph 0x61 1 0,40 + putglyph 0x61 1 0,41 + putglyph 0x61 1 0,42 + putglyph 0x61 1 0,43 + putglyph 0x61 1 0,44 + putglyph 0x61 1 0,45 + putglyph 0x61 1 0,46 + putglyph 0x61 1 0,47 + putglyph 0x61 1 0,48 + putglyph 0x61 1 0,49 + putglyph 0x61 1 0,50 + putglyph 0x61 1 0,51 + putglyph 0x61 1 0,52 + putglyph 0x61 1 0,53 + putglyph 0x61 1 0,54 + putglyph 0x61 1 0,55 + putglyph 0x61 1 0,56 + putglyph 0x61 1 0,57 + putglyph 0x61 1 0,58 + putglyph 0x61 1 0,59 + putglyph 0x61 1 0,60 + putglyph 0x61 1 0,61 + putglyph 0x61 1 0,62 + putglyph 0x61 1 0,63 + putglyph 0x61 1 0,64 + putglyph 0x61 1 0,65 + putglyph 0x61 1 0,66 + putglyph 0x61 1 0,67 + putglyph 0x61 1 0,68 + putglyph 0x61 1 0,69 + putglyph 0x61 1 0,70 + putglyph 0x61 1 0,71 + putglyph 0x61 1 0,72 + putglyph 0x61 1 0,73 + putglyph 0x61 1 0,74 + putglyph 0x61 1 0,75 + putglyph 0x61 1 0,76 + putglyph 0x61 1 0,77 + putglyph 0x61 1 0,78 + putglyph 0x61 1 0,79 + putglyph 0x62 1 1,0 + diff --git a/src/libvterm/t/32state_flow.test b/src/libvterm/t/32state_flow.test new file mode 100644 index 0000000000..84a13df18b --- /dev/null +++ b/src/libvterm/t/32state_flow.test @@ -0,0 +1,28 @@ +INIT +WANTSTATE + +# Many of these test cases inspired by +# https://blueprints.launchpad.net/libvterm/+spec/reflow-cases + +!Spillover text marks continuation on second line +RESET +PUSH "A"x100 +PUSH "\r\n" + ?lineinfo 0 = + ?lineinfo 1 = cont + +!CRLF in column 80 does not mark continuation +RESET +PUSH "B"x80 +PUSH "\r\n" +PUSH "B"x20 +PUSH "\r\n" + ?lineinfo 0 = + ?lineinfo 1 = + +!EL cancels continuation of following line +RESET +PUSH "D"x100 + ?lineinfo 1 = cont +PUSH "\eM\e[79G\e[K" + ?lineinfo 1 = diff --git a/src/libvterm/t/40screen_ascii.test b/src/libvterm/t/60screen_ascii.test similarity index 65% rename from src/libvterm/t/40screen_ascii.test rename to src/libvterm/t/60screen_ascii.test index c2f48fabf3..e679b98af4 100644 --- a/src/libvterm/t/40screen_ascii.test +++ b/src/libvterm/t/60screen_ascii.test @@ -1,12 +1,12 @@ INIT -WANTSCREEN c +WANTSCREEN ac !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_chars 0,0,1,3 = "ABC" + ?screen_chars 0,0,1,80 = "ABC" ?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) @@ -18,11 +18,11 @@ PUSH "ABC" ?screen_eol 0,3 = 1 PUSH "\e[H" movecursor 0,0 - ?screen_chars 0,0,1,80 = 0x41,0x42,0x43 + ?screen_chars 0,0,1,80 = "ABC" ?screen_text 0,0,1,80 = 0x41,0x42,0x43 PUSH "E" movecursor 0,1 - ?screen_chars 0,0,1,80 = 0x45,0x42,0x43 + ?screen_chars 0,0,1,80 = "EBC" ?screen_text 0,0,1,80 = 0x45,0x42,0x43 WANTSCREEN -c @@ -37,33 +37,33 @@ PUSH "ABCDE\e[H\e[K" RESET PUSH "ABC\e[H\e[@" PUSH "1" - ?screen_chars 0,0,1,80 = 0x31,0x41,0x42,0x43 + ?screen_chars 0,0,1,80 = "1ABC" 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 + ?screen_chars 0,0,1,1 = "B" + ?screen_chars 0,1,1,2 = "C" + ?screen_chars 0,0,1,80 = "BC" !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_chars 0,0,1,80 = "Hello World" ?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_chars 0,0,2,80 = "Hello\nWorld" ?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 + ?screen_chars 0,0,1,80 = "P" PUSH "\e[?1049h" ?screen_chars 0,0,1,80 = PUSH "\e[2K\e[HA" - ?screen_chars 0,0,1,80 = 0x41 + ?screen_chars 0,0,1,80 = "A" PUSH "\e[?1049l" - ?screen_chars 0,0,1,80 = 0x50 + ?screen_chars 0,0,1,80 = "P" diff --git a/src/libvterm/t/41screen_unicode.test b/src/libvterm/t/61screen_unicode.test similarity index 100% rename from src/libvterm/t/41screen_unicode.test rename to src/libvterm/t/61screen_unicode.test diff --git a/src/libvterm/t/42screen_damage.test b/src/libvterm/t/62screen_damage.test similarity index 98% rename from src/libvterm/t/42screen_damage.test rename to src/libvterm/t/62screen_damage.test index 791a96cdb9..32cac2d0a1 100644 --- a/src/libvterm/t/42screen_damage.test +++ b/src/libvterm/t/62screen_damage.test @@ -1,5 +1,5 @@ INIT -WANTSCREEN Db +WANTSCREEN aDb !Putglyph RESET @@ -152,4 +152,4 @@ PUSH "\e[25H\r\nABCDE\b\b\b\e[2P\r\n" DAMAGEFLUSH moverect 1..25,0..80 -> 0..24,0..80 damage 24..25,0..80 - ?screen_chars 23,0,24,5 = 0x41,0x42,0x45 + ?screen_chars 23,0,24,5 = "ABE" diff --git a/src/libvterm/t/43screen_resize.test b/src/libvterm/t/63screen_resize.test similarity index 50% rename from src/libvterm/t/43screen_resize.test rename to src/libvterm/t/63screen_resize.test index 9e5e5b206a..87932f66d4 100644 --- a/src/libvterm/t/43screen_resize.test +++ b/src/libvterm/t/63screen_resize.test @@ -6,42 +6,42 @@ WANTSCREEN RESET RESIZE 25,80 PUSH "AB\r\nCD" - ?screen_chars 0,0,1,80 = 0x41,0x42 - ?screen_chars 1,0,2,80 = 0x43,0x44 + ?screen_chars 0,0,1,80 = "AB" + ?screen_chars 1,0,2,80 = "CD" RESIZE 25,100 - ?screen_chars 0,0,1,100 = 0x41,0x42 - ?screen_chars 1,0,2,100 = 0x43,0x44 + ?screen_chars 0,0,1,100 = "AB" + ?screen_chars 1,0,2,100 = "CD" !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 + ?screen_chars 0,0,1,2 = "AB" + ?screen_chars 0,78,1,80 = "CD" RESIZE 25,100 - ?screen_chars 0,0,1,2 = 0x41,0x42 - ?screen_chars 0,78,1,80 = 0x43,0x44 + ?screen_chars 0,0,1,2 = "AB" + ?screen_chars 0,78,1,80 = "CD" PUSH "E" - ?screen_chars 0,78,1,81 = 0x43,0x44,0x45 + ?screen_chars 0,78,1,81 = "CDE" !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 + ?screen_chars 0,0,1,80 = "Top" + ?screen_chars 9,0,10,80 = "Line 10" ?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 + ?screen_chars 0,0,1,80 = "Top" + ?screen_chars 9,0,10,80 = "Line 10" ?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 + ?screen_chars 0,0,1,80 = "Top" + ?screen_chars 24,0,25,80 = "Line 25" ?cursor = 14,0 WANTSCREEN b RESIZE 20,80 @@ -51,7 +51,7 @@ RESIZE 20,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 + ?screen_chars 19,0,20,80 = "Line 25" ?cursor = 9,0 !Resize shorter does not lose line with cursor @@ -62,11 +62,11 @@ 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 + ?screen_chars 23,0,24,10 = "Line 25" ?cursor = 24,0 RESIZE 24,80 sb_pushline 80 = - ?screen_chars 22,0,23,10 = 0x4c,0x69,0x6e,0x65,0x20,0x32,0x35 + ?screen_chars 22,0,23,10 = "Line 25" ?cursor = 23,0 !Resize taller attempts to pop scrollback @@ -74,8 +74,8 @@ 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 + ?screen_chars 0,0,1,80 = "Line 1" + ?screen_chars 24,0,25,80 = "Bottom" ?cursor = 14,0 WANTSCREEN b RESIZE 30,80 @@ -84,7 +84,18 @@ RESIZE 30,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 + ?screen_chars 0,0,1,80 = "ABCDE" + ?screen_chars 5,0,6,80 = "Line 1" + ?screen_chars 29,0,30,80 = "Bottom" ?cursor = 19,0 +WANTSCREEN -b + +!Resize can operate on altscreen +RESET +WANTSCREEN a +RESIZE 25,80 +PUSH "Main screen\e[?1049h\e[HAlt screen" +RESIZE 30,80 + ?screen_chars 0,0,1,3 = "Alt" +PUSH "\e[?1049l" + ?screen_chars 0,0,1,3 = "Mai" diff --git a/src/libvterm/t/44screen_pen.test b/src/libvterm/t/64screen_pen.test similarity index 67% rename from src/libvterm/t/44screen_pen.test rename to src/libvterm/t/64screen_pen.test index f1ee639ac7..3a7814087e 100644 --- a/src/libvterm/t/44screen_pen.test +++ b/src/libvterm/t/64screen_pen.test @@ -29,27 +29,27 @@ PUSH "\e[11mF\e[m" !Foreground PUSH "\e[31mG\e[m" - ?screen_cell 0,6 = {0x47} width=1 attrs={} fg=rgb(224,0,0) bg=rgb(0,0,0) + ?screen_cell 0,6 = {0x47} width=1 attrs={} fg=idx(1) 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) + ?screen_cell 0,7 = {0x48} width=1 attrs={} fg=rgb(240,240,240) bg=idx(2) !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) + ?screen_cell 0,0 = {} width=1 attrs={R} fg=idx(3) bg=idx(4) + ?screen_cell 0,79 = {} width=1 attrs={R} fg=idx(3) bg=idx(4) !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 0,0 = {} width=1 attrs={} fg=idx(3) bg=idx(4) + ?screen_cell 0,79 = {} width=1 attrs={} fg=idx(3) bg=idx(4) ?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 0,0 = {} width=1 attrs={R} fg=idx(3) bg=idx(4) + ?screen_cell 0,79 = {} width=1 attrs={R} fg=idx(3) bg=idx(4) ?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/65screen_protect.test similarity index 100% rename from src/libvterm/t/45screen_protect.test rename to src/libvterm/t/65screen_protect.test diff --git a/src/libvterm/t/46screen_extent.test b/src/libvterm/t/66screen_extent.test similarity index 100% rename from src/libvterm/t/46screen_extent.test rename to src/libvterm/t/66screen_extent.test diff --git a/src/libvterm/t/47screen_dbl_wh.test b/src/libvterm/t/67screen_dbl_wh.test similarity index 77% rename from src/libvterm/t/47screen_dbl_wh.test rename to src/libvterm/t/67screen_dbl_wh.test index 7d17d9a8c3..9c81e83b86 100644 --- a/src/libvterm/t/47screen_dbl_wh.test +++ b/src/libvterm/t/67screen_dbl_wh.test @@ -30,3 +30,9 @@ 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) + +!DWL doesn't spill over on scroll +RESET +PUSH "\e[25H\e#6Final\r\n" + ?screen_cell 23,0 = {0x46} width=1 attrs={} dwl fg=rgb(240,240,240) bg=rgb(0,0,0) + ?screen_cell 24,0 = {} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0) diff --git a/src/libvterm/t/48screen_termprops.test b/src/libvterm/t/68screen_termprops.test similarity index 85% rename from src/libvterm/t/48screen_termprops.test rename to src/libvterm/t/68screen_termprops.test index adf7ec2f74..bba6660e30 100644 --- a/src/libvterm/t/48screen_termprops.test +++ b/src/libvterm/t/68screen_termprops.test @@ -14,4 +14,4 @@ PUSH "\e[?25l" !Title PUSH "\e]2;Here is my title\a" - settermprop 4 "Here is my title" + settermprop 4 ["Here is my title"] diff --git a/src/libvterm/t/harness.c b/src/libvterm/t/harness.c index 75869d756c..10afbfd768 100644 --- a/src/libvterm/t/harness.c +++ b/src/libvterm/t/harness.c @@ -47,6 +47,7 @@ static VTermKey strp_key(char *str) { "Tab", VTERM_KEY_TAB }, { "Enter", VTERM_KEY_ENTER }, { "KP0", VTERM_KEY_KP_0 }, + { "F1", VTERM_KEY_FUNCTION(1) }, { NULL, VTERM_KEY_NONE }, }; int i; @@ -59,6 +60,26 @@ static VTermKey strp_key(char *str) return VTERM_KEY_NONE; } +static void print_color(const VTermColor *col) +{ + if (VTERM_COLOR_IS_RGB(col)) { + printf("rgb(%d,%d,%d", col->red, col->green, col->blue); + } + else if (VTERM_COLOR_IS_INDEXED(col)) { + printf("idx(%d", col->index); + } + else { + printf("invalid(%d", col->type); + } + if (VTERM_COLOR_IS_DEFAULT_FG(col)) { + printf(",is_default_fg"); + } + if (VTERM_COLOR_IS_DEFAULT_BG(col)) { + printf(",is_default_bg"); + } + printf(")"); +} + static VTerm *vt; static VTermState *state; static VTermScreen *screen; @@ -152,21 +173,44 @@ static int parser_csi(const char *leader, const long args[], int argcount, const return 1; } -static int parser_osc(const char *command, size_t cmdlen, void *user UNUSED) +static int parser_osc(int command, VTermStringFragment frag, void *user UNUSED) { printf("osc "); - printhex(command, cmdlen); + + if(frag.initial) { + if(command == -1) + printf("["); + else + printf("[%d;", command); + } + + printhex(frag.str, frag.len); + + if(frag.final) + printf("]"); + printf("\n"); return 1; } -static int parser_dcs(const char *command, size_t cmdlen, void *user UNUSED) +static int parser_dcs(const char *command, size_t commandlen, VTermStringFragment frag, void *user UNUSED) { - printf("dcs "); - printhex(command, cmdlen); + + if(frag.initial) { + size_t i; + printf("["); + for(i = 0; i < commandlen; i++) + printf("%02x", command[i]); + } + + printhex(frag.str, frag.len); + + if(frag.final) + printf("]"); + printf("\n"); return 1; @@ -182,7 +226,14 @@ static VTermParserCallbacks parser_cbs = { NULL // resize }; -// These callbacks are shared by State and Screen +static VTermStateFallbacks fallbacks = { + parser_control, // control + parser_csi, // csi + parser_osc, // osc + parser_dcs // dcs +}; + +/* These callbacks are shared by State and Screen */ static int want_movecursor = 0; static VTermPos state_pos; @@ -238,10 +289,13 @@ static int settermprop(VTermProp prop, VTermValue *val, void *user UNUSED) printf("settermprop %d %d\n", prop, val->number); return 1; case VTERM_VALUETYPE_STRING: - printf("settermprop %d \"%s\"\n", prop, val->string); + printf("settermprop %d %s\"%.*s\"%s\n", prop, + val->string.initial ? "[" : "", val->string.len, val->string.str, val->string.final ? "]" : ""); return 1; case VTERM_VALUETYPE_COLOR: - printf("settermprop %d rgb(%d,%d,%d)\n", prop, val->color.red, val->color.green, val->color.blue); + printf("settermprop %d ", prop); + print_color(&val->color); + printf("\n"); return 1; case VTERM_N_VALUETYPES: @@ -261,7 +315,7 @@ static int state_putglyph(VTermGlyphInfo *info, VTermPos pos, void *user UNUSED) return 1; printf("putglyph "); - for(i = 0; info->chars[i]; i++) + for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && 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) @@ -294,6 +348,7 @@ static struct { int italic; int blink; int reverse; + int conceal; int strike; int font; VTermColor foreground; @@ -317,6 +372,9 @@ static int state_setpenattr(VTermAttr attr, VTermValue *val, void *user UNUSED) case VTERM_ATTR_REVERSE: state_pen.reverse = val->boolean; break; + case VTERM_ATTR_CONCEAL: + state_pen.conceal = val->boolean; + break; case VTERM_ATTR_STRIKE: state_pen.strike = val->boolean; break; @@ -482,6 +540,9 @@ int main(int argc UNUSED, char **argv UNUSED) if(streq(line, "INIT")) { if(!vt) vt = vterm_new(25, 80); + + // Somehow this makes tests fail + // vterm_output_set_callback(vt, term_output, NULL); } else if(streq(line, "WANTPARSER")) { @@ -524,7 +585,7 @@ int main(int argc UNUSED, char **argv UNUSED) want_settermprop = sense; break; case 'f': - vterm_state_set_unrecognised_fallbacks(state, sense ? &parser_cbs : NULL, NULL); + vterm_state_set_unrecognised_fallbacks(state, sense ? &fallbacks : NULL, NULL); break; default: fprintf(stderr, "Unrecognised WANTSTATE flag '%c'\n", line[i]); @@ -536,7 +597,6 @@ int main(int argc UNUSED, char **argv UNUSED) 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] == ' ') @@ -546,6 +606,9 @@ int main(int argc UNUSED, char **argv UNUSED) case '-': sense = 0; break; + case 'a': + vterm_screen_enable_altscreen(screen, 1); + break; case 'd': want_screen_damage = sense; break; @@ -793,14 +856,35 @@ int main(int argc UNUSED, char **argv UNUSED) 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); + print_color(&state_pen.foreground); + printf("\n"); } else if(streq(linep, "background")) { - printf("rgb(%d,%d,%d)\n", state_pen.background.red, state_pen.background.green, state_pen.background.blue); + print_color(&state_pen.background); + printf("\n"); } else printf("?\n"); } + else if(strstartswith(line, "?lineinfo ")) { + char *linep = line + 10; + int row; + const VTermLineInfo *info; + while(linep[0] == ' ') + linep++; + if(sscanf(linep, "%d", &row) < 1) { + printf("! lineinfo unrecognised input\n"); + goto abort_line; + } + info = vterm_state_get_lineinfo(state, row); + if(info->doublewidth) + printf("dwl "); + if(info->doubleheight) + printf("dhl "); + if(info->continuation) + printf("cont "); + printf("\n"); + } else if(strstartswith(line, "?screen_chars ")) { char *linep = line + 13; VTermRect rect; @@ -892,8 +976,13 @@ int main(int argc UNUSED, char **argv UNUSED) 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); + printf("fg="); + vterm_screen_convert_color_to_rgb(screen, &cell.fg); + print_color(&cell.fg); + printf(" bg="); + vterm_screen_convert_color_to_rgb(screen, &cell.bg); + print_color(&cell.bg); + printf("\n"); } else if(strstartswith(line, "?screen_eol ")) { VTermPos pos; diff --git a/src/libvterm/t/run-test.pl b/src/libvterm/t/run-test.pl index 12e11801b6..96f47fb868 100644 --- a/src/libvterm/t/run-test.pl +++ b/src/libvterm/t/run-test.pl @@ -8,14 +8,17 @@ use IPC::Open2 qw( open2 ); use POSIX qw( WIFEXITED WEXITSTATUS WIFSIGNALED WTERMSIG ); my $VALGRIND = 0; +my $EXECUTABLE = "t/.libs/harness"; GetOptions( 'valgrind|v+' => \$VALGRIND, + 'executable|e=s' => \$EXECUTABLE, + 'fail-early|F' => \(my $FAIL_EARLY), ) or exit 1; my ( $hin, $hout, $hpid ); { local $ENV{LD_LIBRARY_PATH} = ".libs"; - my @command = "t/.libs/harness"; + my @command = $EXECUTABLE; 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 - $!"; @@ -26,6 +29,8 @@ my $exitcode = 0; my $command; my @expect; +my $linenum = 0; + sub do_onetest { $hin->print( "$command\n" ); @@ -39,7 +44,7 @@ sub do_onetest chomp $outline; if( !@expect ) { - print "# Test failed\n" unless $fail_printed++; + print "# line $linenum: Test failed\n" unless $fail_printed++; print "# expected nothing more\n" . "# Actual: $outline\n"; next; @@ -49,18 +54,19 @@ sub do_onetest next if $expectation eq $outline; - print "# Test failed\n" unless $fail_printed++; + print "# line $linenum: Test failed\n" unless $fail_printed++; print "# Expected: $expectation\n" . "# Actual: $outline\n"; } if( @expect ) { - print "# Test failed\n" unless $fail_printed++; + print "# line $linenum: Test failed\n" unless $fail_printed++; print "# Expected: $_\n" . "# didn't happen\n" for @expect; } $exitcode = 1 if $fail_printed; + exit $exitcode if $exitcode and $FAIL_EARLY; } sub do_line @@ -101,8 +107,15 @@ sub do_line 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/^(osc) (\[\d+)? *(.*?)(\]?)$/ ) { + my ( $cmd, $initial, $data, $final ) = ( $1, $2, $3, $4 ); + $initial //= ""; + $initial .= ";" if $initial =~ m/\d+/; + + $line = "$cmd $initial" . join( "", map sprintf("%02x", $_), unpack "C*", length $data ? eval($data) : "" ) . "$final"; + } + elsif( $line =~ m/^(escape|dcs) (\[?)(.*?)(\]?)$/ ) { + $line = "$1 $2" . join( "", map sprintf("%02x", $_), unpack "C*", eval($3) ) . "$4"; } elsif( $line =~ m/^putglyph (\S+) (.*)$/ ) { $line = "putglyph " . join( ",", map sprintf("%x", $_), eval($1) ) . " $2"; @@ -131,27 +144,35 @@ sub do_line $response = pack "C*", map hex, split m/,/, $response; if( $response ne $want ) { - print "# Assert ?screen_row $row failed:\n" . + print "# line $linenum: Assert ?screen_row $row failed:\n" . "# Expected: $want\n" . "# Actual: $response\n"; $exitcode = 1; + exit $exitcode if $exitcode and $FAIL_EARLY; } } # Assertions start with '?' - elsif( $line =~ s/^\?([a-z]+.*?=)\s+// ) { + elsif( $line =~ s/^\?([a-z]+.*?=)\s*// ) { do_onetest if defined $command; my ( $assertion ) = $1 =~ m/^(.*)\s+=/; + my $expectation = $line; $hin->print( "\?$assertion\n" ); my $response = <$hout>; defined $response or wait, die "Test harness failed - $?\n"; - chomp $response; + chomp $response; $response =~ s/^\s+|\s+$//g; - if( $response ne $line ) { - print "# Assert $assertion failed:\n" . - "# Expected: $line\n" . + # Some convenience formatting + if( $assertion =~ m/^screen_chars/ and $expectation =~ m/^"/ ) { + $expectation = join ",", map sprintf("0x%02x", ord $_), split m//, eval($expectation); + } + + if( $response ne $expectation ) { + print "# line $linenum: Assert $assertion failed:\n" . + "# Expected: $expectation\n" . "# Actual: $response\n"; $exitcode = 1; + exit $exitcode if $exitcode and $FAIL_EARLY; } } # Test controls start with '$' @@ -174,10 +195,13 @@ sub do_line open my $test, "<", $ARGV[0] or die "Cannot open test script $ARGV[0] - $!"; while( my $line = <$test> ) { + $linenum++; $line =~ s/^\s+//; - next if $line =~ m/^(?:#|$)/; - chomp $line; + + next if $line =~ m/^(?:#|$)/; + last if $line eq "__END__"; + do_line( $line ); } diff --git a/src/list.c b/src/list.c index dfd370b544..7c06cfce57 100644 --- a/src/list.c +++ b/src/list.c @@ -378,8 +378,8 @@ list_equal( if (l1 == NULL || l2 == NULL) return FALSE; - range_list_materialize(l1); - range_list_materialize(l2); + CHECK_LIST_MATERIALIZE(l1); + CHECK_LIST_MATERIALIZE(l2); for (item1 = l1->lv_first, item2 = l2->lv_first; item1 != NULL && item2 != NULL; @@ -411,7 +411,7 @@ list_find(list_T *l, long n) if (n < 0 || n >= l->lv_len) return NULL; - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); // When there is a cached index may start search from there. if (l->lv_u.mat.lv_idx_item != NULL) @@ -541,7 +541,7 @@ list_idx_of_item(list_T *l, listitem_T *item) if (l == NULL) return -1; - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); idx = 0; for (li = l->lv_first; li != NULL && li != item; li = li->li_next) ++idx; @@ -556,7 +556,7 @@ list_idx_of_item(list_T *l, listitem_T *item) void list_append(list_T *l, listitem_T *item) { - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); if (l->lv_u.mat.lv_last == NULL) { // empty list @@ -706,7 +706,7 @@ list_insert_tv(list_T *l, typval_T *tv, listitem_T *item) void list_insert(list_T *l, listitem_T *ni, listitem_T *item) { - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); if (item == NULL) // Append new item at end of list. list_append(l, ni); @@ -741,8 +741,8 @@ list_extend(list_T *l1, list_T *l2, listitem_T *bef) listitem_T *item; int todo = l2->lv_len; - range_list_materialize(l1); - range_list_materialize(l2); + CHECK_LIST_MATERIALIZE(l1); + CHECK_LIST_MATERIALIZE(l2); // 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. @@ -801,7 +801,7 @@ list_copy(list_T *orig, int deep, int copyID) orig->lv_copyID = copyID; orig->lv_copylist = copy; } - range_list_materialize(orig); + CHECK_LIST_MATERIALIZE(orig); for (item = orig->lv_first; item != NULL && !got_int; item = item->li_next) { @@ -842,7 +842,7 @@ vimlist_remove(list_T *l, listitem_T *item, listitem_T *item2) { listitem_T *ip; - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); // notify watchers for (ip = item; ip != NULL; ip = ip->li_next) @@ -877,7 +877,7 @@ list2string(typval_T *tv, int copyID, int restore_copyID) return NULL; ga_init2(&ga, (int)sizeof(char), 80); ga_append(&ga, '['); - range_list_materialize(tv->vval.v_list); + CHECK_LIST_MATERIALIZE(tv->vval.v_list); if (list_join(&ga, tv->vval.v_list, (char_u *)", ", FALSE, restore_copyID, copyID) == FAIL) { @@ -915,7 +915,7 @@ list_join_inner( char_u *s; // Stringify each item in the list. - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); for (item = l->lv_first; item != NULL && !got_int; item = item->li_next) { s = echo_string_core(&item->li_tv, &tofree, numbuf, copyID, @@ -1046,8 +1046,9 @@ f_join(typval_T *argvars, typval_T *rettv) * Return OK or FAIL. */ int -get_list_tv(char_u **arg, typval_T *rettv, int evaluate, int do_error) +get_list_tv(char_u **arg, typval_T *rettv, int flags, int do_error) { + int evaluate = flags & EVAL_EVALUATE; list_T *l = NULL; typval_T tv; listitem_T *item; @@ -1062,7 +1063,7 @@ get_list_tv(char_u **arg, typval_T *rettv, int evaluate, int do_error) *arg = skipwhite(*arg + 1); while (**arg != ']' && **arg != NUL) { - if (eval1(arg, &tv, evaluate) == FAIL) // recursive! + if (eval1(arg, &tv, flags) == FAIL) // recursive! goto failret; if (evaluate) { @@ -1116,7 +1117,7 @@ write_list(FILE *fd, list_T *list, int binary) int ret = OK; char_u *s; - range_list_materialize(list); + CHECK_LIST_MATERIALIZE(list); FOR_ALL_LIST_ITEMS(list, li) { for (s = tv_get_string(&li->li_tv); *s != NUL; ++s) @@ -1203,7 +1204,7 @@ f_list2str(typval_T *argvars, typval_T *rettv) if (argvars[1].v_type != VAR_UNKNOWN) utf8 = (int)tv_get_number_chk(&argvars[1], NULL); - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); ga_init2(&ga, 1, 80); if (has_mbyte || utf8) { @@ -1496,7 +1497,7 @@ do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort) TRUE)) goto theend; rettv_list_set(rettv, l); - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); len = list_len(l); if (len <= 1) @@ -1767,7 +1768,7 @@ filter_map(typval_T *argvars, typval_T *rettv, int map) } else { - semsg(_(e_listdictarg), ermsg); + semsg(_(e_listdictblobarg), ermsg); return; } @@ -1873,7 +1874,7 @@ filter_map(typval_T *argvars, typval_T *rettv, int map) // set_vim_var_nr() doesn't set the type set_vim_var_type(VV_KEY, VAR_NUMBER); - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); if (map && l->lv_lock == 0) l->lv_lock = VAR_LOCKED; for (li = l->lv_first; li != NULL; li = nli) @@ -2011,7 +2012,7 @@ f_count(typval_T *argvars, typval_T *rettv) if ((l = argvars[0].vval.v_list) != NULL) { - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); li = l->lv_first; if (argvars[2].v_type != VAR_UNKNOWN) { @@ -2167,6 +2168,9 @@ f_insert(typval_T *argvars, typval_T *rettv) int val, len; char_u *p; + if (argvars[0].vval.v_blob == NULL) + return; + len = blob_len(argvars[0].vval.v_blob); if (argvars[2].v_type != VAR_UNKNOWN) { diff --git a/src/macros.h b/src/macros.h index 9a3d4e13cf..2ac705d4a1 100644 --- a/src/macros.h +++ b/src/macros.h @@ -373,3 +373,9 @@ # define ESTACK_CHECK_NOW # define CHECK_CURBUF #endif + +// Inline the condition for performance. +#define CHECK_LIST_MATERIALIZE(l) if ((l)->lv_first == &range_list_item) range_list_materialize(l) + +// Inlined version of ga_grow(). Especially useful if "n" is a constant. +#define GA_GROW(gap, n) (((gap)->ga_maxlen - (gap)->ga_len < n) ? ga_grow_inner((gap), (n)) : OK) diff --git a/src/main.c b/src/main.c index b7c8c40f4e..07d10e225b 100644 --- a/src/main.c +++ b/src/main.c @@ -1652,6 +1652,7 @@ getout(int exitval) tabpage_T *next_tp; buf_T *buf; win_T *wp; + int unblock = 0; // Trigger BufWinLeave for all windows, but only once per buffer. for (tp = first_tabpage; tp != NULL; tp = next_tp) @@ -1693,7 +1694,17 @@ getout(int exitval) // autocmd deleted the buffer break; } + + // deathtrap() blocks autocommands, but we do want to trigger + // VimLeavePre. + if (is_autocmd_blocked()) + { + unblock_autocmds(); + ++unblock; + } apply_autocmds(EVENT_VIMLEAVEPRE, NULL, NULL, FALSE, curbuf); + if (unblock) + block_autocmds(); } #ifdef FEAT_VIMINFO @@ -3647,7 +3658,7 @@ usage(void) #endif #if (defined(UNIX) || defined(VMS)) && defined(FEAT_X11) # if defined(FEAT_GUI_X11) && !defined(FEAT_GUI_GTK) - main_msg(_("-display \tConnect vim to this particular X-server")); + main_msg(_("-display \tConnect Vim to this particular X-server")); # endif main_msg(_("-X\t\t\tDo not connect to X server")); #endif @@ -3684,8 +3695,8 @@ usage(void) # endif # endif # endif - main_msg(_("-display \tRun vim on ")); - main_msg(_("-iconic\t\tStart vim iconified")); + main_msg(_("-display \tRun Vim on ")); + main_msg(_("-iconic\t\tStart Vim iconified")); main_msg(_("-background \tUse for the background (also: -bg)")); main_msg(_("-foreground \tUse for normal text (also: -fg)")); main_msg(_("-font \t\tUse for normal text (also: -fn)")); @@ -3706,7 +3717,7 @@ usage(void) main_msg(_("-font \t\tUse for normal text (also: -fn)")); main_msg(_("-geometry \tUse for initial geometry (also: -geom)")); main_msg(_("-reverse\t\tUse reverse video (also: -rv)")); - main_msg(_("-display \tRun vim on (also: --display)")); + main_msg(_("-display \tRun Vim on (also: --display)")); main_msg(_("--role \tSet a unique role to identify the main window")); main_msg(_("--socketid \tOpen Vim inside another GTK widget")); main_msg(_("--echo-wid\t\tMake gvim echo the Window ID on stdout")); diff --git a/src/map.c b/src/map.c index c15139604b..c9a2a8d3e1 100644 --- a/src/map.c +++ b/src/map.c @@ -204,6 +204,86 @@ showmap( out_flush(); // show one line at a time } + static int +map_add( + mapblock_T **map_table, + mapblock_T **abbr_table, + char_u *keys, + char_u *rhs, + char_u *orig_rhs, + int noremap, + int nowait, + int silent, + int mode, + int is_abbr, +#ifdef FEAT_EVAL + int expr, + scid_T sid, // -1 to use current_sctx + linenr_T lnum, +#endif + int simplified) +{ + mapblock_T *mp = ALLOC_ONE(mapblock_T); + + if (mp == NULL) + return FAIL; + + // If CTRL-C has been mapped, don't always use it for Interrupting. + if (*keys == Ctrl_C) + { + if (map_table == curbuf->b_maphash) + curbuf->b_mapped_ctrl_c |= mode; + else + 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); + return FAIL; + } + mp->m_keylen = (int)STRLEN(mp->m_keys); + mp->m_noremap = noremap; + mp->m_nowait = nowait; + mp->m_silent = silent; + mp->m_mode = mode; + mp->m_simplified = simplified; +#ifdef FEAT_EVAL + mp->m_expr = expr; + if (sid >= 0) + { + mp->m_script_ctx.sc_sid = sid; + mp->m_script_ctx.sc_lnum = lnum; + } + else + { + 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 (is_abbr) + { + mp->m_next = *abbr_table; + *abbr_table = mp; + } + else + { + int n = MAP_HASH(mp->m_mode, mp->m_keys[0]); + + mp->m_next = map_table[n]; + map_table[n] = mp; + } + return OK; +} + /* * map[!] : show all key mappings * map[!] {lhs} : show key mapping for {lhs} @@ -501,7 +581,8 @@ do_map( msg_start(); // Check if a new local mapping wasn't already defined globally. - if (map_table == curbuf->b_maphash && haskey && hasarg && maptype != 1) + if (unique && 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) @@ -519,7 +600,6 @@ do_map( // 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) @@ -759,58 +839,16 @@ do_map( continue; // have added the new entry already // Get here when adding a new entry to the maphash[] list or abbrlist. - mp = ALLOC_ONE(mapblock_T); - if (mp == NULL) + if (map_add(map_table, abbr_table, keys, rhs, orig_rhs, + noremap, nowait, silent, mode, abbrev, +#ifdef FEAT_EVAL + expr, /* sid */ -1, /* lnum */ 0, +#endif + did_simplify && keyround == 1) == FAIL) { retval = 4; // no mem goto theend; } - - // If CTRL-C has been mapped, don't always use it for Interrupting. - if (*keys == Ctrl_C) - { - if (map_table == curbuf->b_maphash) - curbuf->b_mapped_ctrl_c |= mode; - else - 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; - mp->m_simplified = did_simplify && keyround == 1; -#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: @@ -1570,14 +1608,14 @@ eval_map_expr( // Forbid changing text or using ":normal" to avoid most of the bad side // effects. Also restore the cursor position. - ++textlock; + ++textwinlock; ++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; + --textwinlock; --ex_normal_lock; curwin->w_cursor = save_cursor; msg_col = save_msg_col; @@ -2138,15 +2176,20 @@ check_map( get_maparg(typval_T *argvars, typval_T *rettv, int exact) { char_u *keys; + char_u *keys_simplified; char_u *which; char_u buf[NUMBUFLEN]; char_u *keys_buf = NULL; + char_u *alt_keys_buf = NULL; + int did_simplify = FALSE; char_u *rhs; int mode; int abbr = FALSE; int get_dict = FALSE; mapblock_T *mp; + mapblock_T *mp_simplified; int buffer_local; + int flags = REPTERM_FROM_PART | REPTERM_DO_LT; // return empty string for failure rettv->v_type = VAR_STRING; @@ -2173,10 +2216,20 @@ get_maparg(typval_T *argvars, typval_T *rettv, int exact) mode = get_map_mode(&which, 0); - keys = replace_termcodes(keys, &keys_buf, - REPTERM_FROM_PART | REPTERM_DO_LT, NULL); - rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local); - vim_free(keys_buf); + keys_simplified = replace_termcodes(keys, &keys_buf, flags, &did_simplify); + rhs = check_map(keys_simplified, mode, exact, FALSE, abbr, + &mp, &buffer_local); + if (did_simplify) + { + // When the lhs is being simplified the not-simplified keys are + // preferred for priting, like in do_map(). + // The "rhs" and "buffer_local" values are not expected to change. + mp_simplified = mp; + (void)replace_termcodes(keys, &alt_keys_buf, + flags | REPTERM_NO_SIMPLIFY, NULL); + rhs = check_map(alt_keys_buf, mode, exact, FALSE, abbr, &mp, + &buffer_local); + } if (!get_dict) { @@ -2198,6 +2251,11 @@ get_maparg(typval_T *argvars, typval_T *rettv, int exact) dict_T *dict = rettv->vval.v_dict; dict_add_string(dict, "lhs", lhs); + vim_free(lhs); + dict_add_string(dict, "lhsraw", mp->m_keys); + if (did_simplify) + // Also add the value for the simplified entry. + dict_add_string(dict, "lhsrawalt", mp_simplified->m_keys); dict_add_string(dict, "rhs", mp->m_orig_str); dict_add_number(dict, "noremap", mp->m_noremap ? 1L : 0L); dict_add_number(dict, "script", mp->m_noremap == REMAP_SCRIPT @@ -2210,12 +2268,99 @@ get_maparg(typval_T *argvars, typval_T *rettv, int exact) dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L); dict_add_string(dict, "mode", mapmode); - vim_free(lhs); vim_free(mapmode); } + + vim_free(keys_buf); + vim_free(alt_keys_buf); +} + +/* + * "mapset()" function + */ + void +f_mapset(typval_T *argvars, typval_T *rettv UNUSED) +{ + char_u *keys_buf = NULL; + char_u *which; + int mode; + char_u buf[NUMBUFLEN]; + int is_abbr; + dict_T *d; + char_u *lhs; + char_u *lhsraw; + char_u *lhsrawalt; + char_u *rhs; + char_u *orig_rhs; + char_u *arg_buf = NULL; + int noremap; + int expr; + int silent; + scid_T sid; + linenr_T lnum; + mapblock_T **map_table = maphash; + mapblock_T **abbr_table = &first_abbr; + int nowait; + char_u *arg; + + which = tv_get_string_buf_chk(&argvars[0], buf); + mode = get_map_mode(&which, 0); + is_abbr = (int)tv_get_number(&argvars[1]); + + if (argvars[2].v_type != VAR_DICT) + { + emsg(_(e_dictkey)); + return; + } + d = argvars[2].vval.v_dict; + + // Get the values in the same order as above in get_maparg(). + lhs = dict_get_string(d, (char_u *)"lhs", FALSE); + lhsraw = dict_get_string(d, (char_u *)"lhsraw", FALSE); + lhsrawalt = dict_get_string(d, (char_u *)"lhsrawalt", FALSE); + rhs = dict_get_string(d, (char_u *)"rhs", FALSE); + if (lhs == NULL || lhsraw == NULL || rhs == NULL) + { + emsg(_("E460: entries missing in mapset() dict argument")); + return; + } + orig_rhs = rhs; + rhs = replace_termcodes(rhs, &arg_buf, + REPTERM_DO_LT | REPTERM_SPECIAL, NULL); + + noremap = dict_get_number(d, (char_u *)"noremap") ? REMAP_NONE: 0; + if (dict_get_number(d, (char_u *)"script") != 0) + noremap = REMAP_SCRIPT; + expr = dict_get_number(d, (char_u *)"expr") != 0; + silent = dict_get_number(d, (char_u *)"silent") != 0; + sid = dict_get_number(d, (char_u *)"sid"); + lnum = dict_get_number(d, (char_u *)"lnum"); + if (dict_get_number(d, (char_u *)"buffer")) + { + map_table = curbuf->b_maphash; + abbr_table = &curbuf->b_first_abbr; + } + nowait = dict_get_number(d, (char_u *)"nowait") != 0; + // mode from the dict is not used + + // Delete any existing mapping for this lhs and mode. + arg = vim_strsave(lhs); + if (arg == NULL) + return; + do_map(1, arg, mode, is_abbr); + vim_free(arg); + + (void)map_add(map_table, abbr_table, lhsraw, rhs, orig_rhs, noremap, + nowait, silent, mode, is_abbr, expr, sid, lnum, 0); + if (lhsrawalt != NULL) + (void)map_add(map_table, abbr_table, lhsrawalt, rhs, orig_rhs, noremap, + nowait, silent, mode, is_abbr, expr, sid, lnum, 1); + vim_free(keys_buf); + vim_free(arg_buf); } #endif + #if defined(MSWIN) || defined(MACOS_X) # define VIS_SEL (VISUAL+SELECTMODE) // abbreviation diff --git a/src/menu.c b/src/menu.c index ca76af2079..0e24a4fc3c 100644 --- a/src/menu.c +++ b/src/menu.c @@ -2709,7 +2709,7 @@ ex_menutranslate(exarg_T *eap UNUSED) /* * ":menutrans clear": clear all translations. */ - if (STRNCMP(arg, "clear", 5) == 0 && ends_excmd(*skipwhite(arg + 5))) + if (STRNCMP(arg, "clear", 5) == 0 && ends_excmd2(arg, skipwhite(arg + 5))) { tp = (menutrans_T *)menutrans_ga.ga_data; for (i = 0; i < menutrans_ga.ga_len; ++i) @@ -2732,7 +2732,9 @@ ex_menutranslate(exarg_T *eap UNUSED) to = skipwhite(arg); *arg = NUL; arg = menu_skip_part(to); - if (arg == to) + if (arg == to || ends_excmd2(eap->arg, from) + || ends_excmd2(eap->arg, to) + || !ends_excmd2(eap->arg, skipwhite(arg))) emsg(_(e_invarg)); else { diff --git a/src/message.c b/src/message.c index db1f92db58..03a2fdbb6c 100644 --- a/src/message.c +++ b/src/message.c @@ -1035,7 +1035,11 @@ ex_messages(exarg_T *eap) if (p == first_msg_hist) { +#ifdef FEAT_MULTI_LANG + s = get_mess_lang(); +#else s = mch_getenv((char_u *)"LANG"); +#endif if (s != NULL && *s != NUL) // The next comment is extracted by xgettext and put in po file for // translators to read. diff --git a/src/message_test.c b/src/message_test.c index 014d8d9d45..85a29b4712 100644 --- a/src/message_test.c +++ b/src/message_test.c @@ -127,7 +127,7 @@ test_vim_snprintf(void) int n; size_t bsize; int bsize_int; - char *ptr = (char *)0x87654321; + void *ptr = (void *)0x87654321; // Loop on various buffer sizes to make sure that truncation of // vim_snprintf() is correct. diff --git a/src/misc1.c b/src/misc1.c index b9a2526677..f2eed67649 100644 --- a/src/misc1.c +++ b/src/misc1.c @@ -1673,23 +1673,25 @@ vim_getenv(char_u *name, int *mustfree) if (p != NULL) return p; + +# ifdef __HAIKU__ + // special handling for user settings directory... + if (STRCMP(name, "BE_USER_SETTINGS") == 0) + { + static char userSettingsPath[MAXPATHL]; + + if (find_directory(B_USER_SETTINGS_DIRECTORY, 0, false, + userSettingsPath, MAXPATHL) == B_OK) + return (char_u *)userSettingsPath; + else + return NULL; + } +# endif #endif // handling $VIMRUNTIME and $VIM is below, bail out if it's another name. vimruntime = (STRCMP(name, "VIMRUNTIME") == 0); if (!vimruntime && STRCMP(name, "VIM") != 0) -#if defined(__HAIKU__) - // special handling for user settings directory... - if (STRCMP(name, "BE_USER_SETTINGS") == 0) - { - static char userSettingsPath[MAXPATHL] = {0}; - - if (B_OK == find_directory(B_USER_SETTINGS_DIRECTORY, 0, - false, userSettingsPath, MAXPATHL)) - return userSettingsPath; - } - else -#endif return NULL; /* @@ -2179,7 +2181,7 @@ preserve_exit(void) { if (buf->b_ml.ml_mfp != NULL && buf->b_ml.ml_mfp->mf_fname != NULL) { - OUT_STR("Vim: preserving files...\n"); + OUT_STR("Vim: preserving files...\r\n"); screen_start(); // don't know where cursor is now out_flush(); ml_sync_all(FALSE, FALSE); // preserve all swap files @@ -2189,7 +2191,7 @@ preserve_exit(void) ml_close_all(FALSE); // close all memfiles, without deleting - OUT_STR("Vim: Finished.\n"); + OUT_STR("Vim: Finished.\r\n"); getout(1); } diff --git a/src/misc2.c b/src/misc2.c index 145005f1a1..fd718ba701 100644 --- a/src/misc2.c +++ b/src/misc2.c @@ -1069,6 +1069,10 @@ free_all_mem(void) # if defined(FEAT_BEVAL_TERM) ui_remove_balloon(); # endif +# ifdef FEAT_PROP_POPUP + if (curwin != NULL) + close_all_popups(TRUE); +# endif // Clear user commands (before deleting buffers). ex_comclear(NULL); @@ -2049,31 +2053,36 @@ ga_init2(garray_T *gap, int itemsize, int growsize) */ int ga_grow(garray_T *gap, int n) +{ + if (gap->ga_maxlen - gap->ga_len < n) + return ga_grow_inner(gap, n); + return OK; +} + + int +ga_grow_inner(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; + if (n < gap->ga_growsize) + n = gap->ga_growsize; - // A linear growth is very inefficient when the array grows big. This - // is a compromise between allocating memory that won't be used and too - // many copy operations. A factor of 1.5 seems reasonable. - if (n < gap->ga_len / 2) - n = gap->ga_len / 2; + // A linear growth is very inefficient when the array grows big. This + // is a compromise between allocating memory that won't be used and too + // many copy operations. A factor of 1.5 seems reasonable. + if (n < gap->ga_len / 2) + n = gap->ga_len / 2; - new_len = gap->ga_itemsize * (gap->ga_len + n); - pp = 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; - } + new_len = gap->ga_itemsize * (gap->ga_len + n); + pp = 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; } @@ -3151,8 +3160,7 @@ call_shell(char_u *cmd, int opt) if (p_verbose > 3) { verbose_enter(); - smsg(_("Calling shell to execute: \"%s\""), - cmd == NULL ? p_sh : cmd); + smsg(_("Calling shell to execute: \"%s\""), cmd == NULL ? p_sh : cmd); out_char('\n'); cursor_on(); verbose_leave(); diff --git a/src/normal.c b/src/normal.c index 13f4155320..3de1da7e80 100644 --- a/src/normal.c +++ b/src/normal.c @@ -4181,6 +4181,10 @@ nv_gotofile(cmdarg_T *cap) clearop(cap->oap); return; } +#ifdef FEAT_PROP_POPUP + if (ERROR_IF_TERM_POPUP_WINDOW) + return; +#endif ptr = grab_file_name(cap->count1, &lnum); diff --git a/src/ops.c b/src/ops.c index 5e9de4d7cc..9ab355596b 100644 --- a/src/ops.c +++ b/src/ops.c @@ -17,8 +17,6 @@ static void shift_block(oparg_T *oap, int amount); static void mb_adjust_opend(oparg_T *oap); static int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1); -static int ends_in_white(linenr_T lnum); -static int fmt_check_par(linenr_T, int *, char_u **, int do_comments); // Flags for third item in "opchars". #define OPF_LINES 1 // operator always works on lines @@ -590,46 +588,6 @@ block_insert( State = oldstate; } -/* - * Stuff a string into the typeahead buffer, such that edit() will insert it - * literally ("literally" TRUE) or interpret is as typed characters. - */ - 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); - } - } -} - /* * Handle a delete operation. * @@ -2170,554 +2128,6 @@ theend: return ret; } -/* - * 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); -} - -/* - * Implementation of the format operator 'gq'. - */ - static 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); - - if (!cmdmod.lockmarks) - // 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); - - if (!cmdmod.lockmarks) - // 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'. - */ - static 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; - 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' - 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' - do_comments = has_format_option(FO_Q_COMS); - 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 - , &leader_len, &leader_flags, do_comments); - else - is_not_par = TRUE; - next_is_not_par = fmt_check_par(curwin->w_cursor.lnum - , &next_leader_len, &next_leader_flags, do_comments); - 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; - leader_len = next_leader_len; - leader_flags = next_leader_flags; - } - - /* - * The last line to be formatted. - */ - if (count == 1 || curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count) - { - next_is_not_par = TRUE; - next_leader_len = 0; - next_leader_flags = NULL; - } - else - { - next_is_not_par = fmt_check_par(curwin->w_cursor.lnum + 1 - , &next_leader_len, &next_leader_flags, do_comments); - 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)) - { - if (leader_len == 0 && next_leader_len == 0) - { - // no comment found - second_indent = - get_indent_lnum(curwin->w_cursor.lnum + 1); - } - else - { - second_indent = next_leader_len; - do_comments_list = 1; - } - } - else if (do_number_indent) - { - if (leader_len == 0 && next_leader_len == 0) - { - // no comment found - second_indent = - get_number_indent(curwin->w_cursor.lnum); - } - else - { - // get_number_indent() is now "comment aware"... - second_indent = - get_number_indent(curwin->w_cursor.lnum); - do_comments_list = 1; - } - } - } - - /* - * When the comment leader changes, it's the end of the paragraph. - */ - if (curwin->w_cursor.lnum >= curbuf->b_ml.ml_line_count - || !same_leader(curwin->w_cursor.lnum, - leader_len, leader_flags, - next_leader_len, next_leader_flags)) - 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 - + (do_comments ? INSCHAR_DO_COM : 0) - + (do_comments && do_comments_list - ? INSCHAR_COM_LIST : 0) - + (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; - 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 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. - */ - 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)); -} - -/* - * 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; - 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 - - if (lnum <= 1) - return TRUE; // start of the file - - p = ml_get(lnum - 1); - if (*p == NUL) - return TRUE; // after empty line - - do_comments = has_format_option(FO_Q_COMS); - if (fmt_check_par(lnum - 1, &leader_len, &leader_flags, do_comments)) - return TRUE; // after non-paragraph line - - if (fmt_check_par(lnum, &next_leader_len, &next_leader_flags, do_comments)) - 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". - - if (!same_leader(lnum - 1, leader_len, leader_flags, - next_leader_len, next_leader_flags)) - return TRUE; // change of comment leader. - - return FALSE; -} - /* * prepare a few things for block mode yank/delete/tilde * diff --git a/src/option.c b/src/option.c index 12f00627d9..c6c437711c 100644 --- a/src/option.c +++ b/src/option.c @@ -2483,7 +2483,9 @@ set_option_sctx_idx(int opt_idx, int opt_flags, sctx_T script_ctx) int indir = (int)options[opt_idx].indir; sctx_T new_script_ctx = script_ctx; - new_script_ctx.sc_lnum += SOURCING_LNUM; + // Modeline already has the line number set. + if (!(opt_flags & OPT_MODELINE)) + 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. @@ -6607,18 +6609,6 @@ wc_use_keyname(char_u *varp, long *wcp) return FALSE; } -/* - * 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. diff --git a/src/optiondefs.h b/src/optiondefs.h index a1248f4abc..9e277062ff 100644 --- a/src/optiondefs.h +++ b/src/optiondefs.h @@ -2917,7 +2917,7 @@ static struct vimoption options[] = {"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, + {"wildoptions", "wop", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP, (char_u *)&p_wop, PV_NONE, {(char_u *)"", (char_u *)0L} SCTX_INIT}, diff --git a/src/optionstr.c b/src/optionstr.c index be6236e34a..b1def8078b 100644 --- a/src/optionstr.c +++ b/src/optionstr.c @@ -1167,8 +1167,11 @@ did_set_string_option( 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); + changed_internal(); + } } else if (gvarp == &p_cm) diff --git a/src/os_amiga.c b/src/os_amiga.c index 1e3fd4b201..850c26acda 100644 --- a/src/os_amiga.c +++ b/src/os_amiga.c @@ -977,7 +977,7 @@ mch_exit(int r) * it sends a 0 to the console to make it back into a CON: from a RAW: */ void -mch_settmode(int tmode) +mch_settmode(tmode_T tmode) { #if defined(__AROS__) || defined(__amigaos4__) if (!SetMode(raw_in, tmode == TMODE_RAW ? 1 : 0)) @@ -1387,7 +1387,11 @@ mch_call_shell( if ((mydir = CurrentDir(mydir)) != 0) // make sure we stay in the same directory UnLock(mydir); if (tmode == TMODE_RAW) + { + // The shell may have messed with the mode, always set it. + cur_tmode = TMODE_UNKNOWN; settmode(TMODE_RAW); // set to raw mode + } #ifdef FEAT_TITLE resettitle(); #endif diff --git a/src/os_haiku.rdef b/src/os_haiku.rdef.in similarity index 99% rename from src/os_haiku.rdef rename to src/os_haiku.rdef.in index bf55aa9a9b..64ba9f4a10 100644 --- a/src/os_haiku.rdef +++ b/src/os_haiku.rdef.in @@ -1,12 +1,11 @@ /* - * os_haiku.rdef + * os_haiku.rdef.in: Assets and resources file for Haiku */ resource app_signature "application/x-vnd.Haiku-Vim-8"; resource app_version { major = @MAJOR@, - middle = @MIDDLE@, minor = @MINOR@, variety = B_APPV_FINAL, diff --git a/src/os_mswin.c b/src/os_mswin.c index 1c987c2d62..80009533c6 100644 --- a/src/os_mswin.c +++ b/src/os_mswin.c @@ -553,7 +553,7 @@ vim_stat(const char *name, stat_T *stp) #if (defined(FEAT_GUI_MSWIN) && !defined(VIMDLL)) || defined(PROTO) void -mch_settmode(int tmode UNUSED) +mch_settmode(tmode_T tmode UNUSED) { // nothing to do } diff --git a/src/os_unix.c b/src/os_unix.c index c166906545..eb46b78c74 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -129,6 +129,8 @@ Window x11_window = 0; Display *x11_display = NULL; #endif +static int ignore_sigtstp = FALSE; + #ifdef FEAT_TITLE static int get_x11_title(int); @@ -213,7 +215,8 @@ static volatile sig_atomic_t in_mch_delay = FALSE; // sleeping in mch_delay() static int dont_check_job_ended = 0; #endif -static int curr_tmode = TMODE_COOK; // contains current terminal mode +// Current terminal mode from mch_settmode(). Can differ from cur_tmode. +static tmode_T mch_cur_tmode = TMODE_COOK; #ifdef USE_XSMP typedef struct @@ -579,7 +582,7 @@ mch_total_mem(int special UNUSED) void mch_delay(long msec, int ignoreinput) { - int old_tmode; + tmode_T old_tmode; #ifdef FEAT_MZSCHEME long total = msec; // remember original value #endif @@ -589,9 +592,10 @@ mch_delay(long msec, int 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). + // Only do this if sleeping for more than half a second. in_mch_delay = TRUE; - old_tmode = curr_tmode; - if (curr_tmode == TMODE_RAW) + old_tmode = mch_cur_tmode; + if (mch_cur_tmode == TMODE_RAW && msec > 500) settmode(TMODE_SLEEP); /* @@ -648,7 +652,8 @@ mch_delay(long msec, int ignoreinput) while (total > 0); #endif - settmode(old_tmode); + if (msec > 500) + settmode(old_tmode); in_mch_delay = FALSE; } else @@ -1083,10 +1088,10 @@ deathtrap SIGDEFARG(sigarg) // No translation, it may call malloc(). #ifdef SIGHASARG - sprintf((char *)IObuff, "Vim: Caught deadly signal %s\n", + sprintf((char *)IObuff, "Vim: Caught deadly signal %s\r\n", signal_info[i].name); #else - sprintf((char *)IObuff, "Vim: Caught deadly signal\n"); + sprintf((char *)IObuff, "Vim: Caught deadly signal\r\n"); #endif // Preserve files and exit. This sets the really_exiting flag to prevent @@ -1237,6 +1242,9 @@ restore_clipboard(void) void mch_suspend(void) { + if (ignore_sigtstp) + return; + // BeOS does have SIGTSTP, but it doesn't work. #if defined(SIGTSTP) && !defined(__BEOS__) in_mch_suspend = TRUE; @@ -1286,6 +1294,14 @@ mch_init(void) Rows = 24; out_flush(); + +#ifdef SIGTSTP + // Check whether we were invoked with SIGTSTP set to be ignored. If it is + // that indicates the shell (or program) that launched us does not support + // tty job control and thus we should ignore that signal. If invoked as a + // restricted editor (e.g., as "rvim") SIGTSTP is always ignored. + ignore_sigtstp = restricted || SIG_IGN == signal(SIGTSTP, SIG_ERR); +#endif set_signals(); #ifdef MACOS_CONVERT @@ -1306,17 +1322,13 @@ set_signals(void) 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); + // See mch_init() for the conditions under which we ignore SIGTSTP. + signal(SIGTSTP, ignore_sigtstp ? SIG_IGN : SIG_DFL); #endif #if defined(SIGCONT) signal(SIGCONT, sigcont_handler); #endif - /* * We want to ignore breaking of PIPEs. */ @@ -1386,6 +1398,7 @@ catch_signals( int i; for (i = 0; signal_info[i].sig != -1; i++) + { if (signal_info[i].deadly) { #if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION) @@ -1420,7 +1433,17 @@ catch_signals( #endif } else if (func_other != SIG_ERR) + { + // Deal with non-deadly signals. +#ifdef SIGTSTP + signal(signal_info[i].sig, + signal_info[i].sig == SIGTSTP && ignore_sigtstp + ? SIG_IGN : func_other); +#else signal(signal_info[i].sig, func_other); +#endif + } + } } #ifdef HAVE_SIGPROCMASK @@ -1544,10 +1567,15 @@ 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 + // In the GUI we cannot print a message and continue, because no X calls + // are allowed here (causes my system to hang). Silently continuing seems + // like the best alternative. Do preserve files, in case we crash. + ml_sync_all(FALSE, FALSE); + +#ifdef FEAT_GUI + if (!gui.in_use) +#endif + msg((char *)IObuff); return 0; // NOTREACHED } @@ -3293,6 +3321,10 @@ exit_scroll(void) } } +#ifdef USE_GCOV_FLUSH +extern void __gcov_flush(); +#endif + void mch_exit(int r) { @@ -3339,6 +3371,12 @@ mch_exit(int r) } out_flush(); ml_close_all(TRUE); // remove all memfiles + +#ifdef USE_GCOV_FLUSH + // Flush coverage info before possibly being killed by a deadly signal. + __gcov_flush(); +#endif + may_core_dump(); #ifdef FEAT_GUI if (gui.in_use) @@ -3432,7 +3470,7 @@ mch_tcgetattr(int fd, void *term) } void -mch_settmode(int tmode) +mch_settmode(tmode_T tmode) { static int first = TRUE; @@ -3529,7 +3567,7 @@ mch_settmode(int tmode) ttybnew.sg_flags &= ~(ECHO); ioctl(read_cmd_fd, TIOCSETN, &ttybnew); #endif - curr_tmode = tmode; + mch_cur_tmode = tmode; } /* @@ -4166,11 +4204,6 @@ set_child_environment( 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); @@ -4180,7 +4213,7 @@ set_child_environment( setenv("LINES", (char *)envbuf, 1); sprintf((char *)envbuf, "%ld", columns); setenv("COLUMNS", (char *)envbuf, 1); - sprintf((char *)envbuf, "%ld", colors); + sprintf((char *)envbuf, "%d", t_colors); setenv("COLORS", (char *)envbuf, 1); # ifdef FEAT_TERMINAL if (is_terminal) @@ -4207,7 +4240,7 @@ set_child_environment( vim_snprintf(envbuf_Columns, sizeof(envbuf_Columns), "COLUMNS=%ld", columns); putenv(envbuf_Columns); - vim_snprintf(envbuf_Colors, sizeof(envbuf_Colors), "COLORS=%ld", colors); + vim_snprintf(envbuf_Colors, sizeof(envbuf_Colors), "COLORS=%ld", t_colors); putenv(envbuf_Colors); # ifdef FEAT_TERMINAL if (is_terminal) @@ -4431,7 +4464,7 @@ mch_call_shell_system( char *ifn = NULL; char *ofn = NULL; #endif - int tmode = cur_tmode; + tmode_T tmode = cur_tmode; char_u *newcmd; // only needed for unix int x; @@ -4503,7 +4536,11 @@ mch_call_shell_system( } if (tmode == TMODE_RAW) + { + // The shell may have messed with the mode, always set it. + cur_tmode = TMODE_UNKNOWN; settmode(TMODE_RAW); // set to raw mode + } # ifdef FEAT_TITLE resettitle(); # endif @@ -4527,7 +4564,7 @@ mch_call_shell_fork( char_u *cmd, int options) // SHELL_*, see vim.h { - int tmode = cur_tmode; + tmode_T tmode = cur_tmode; pid_t pid; pid_t wpid = 0; pid_t wait_pid = 0; @@ -4559,6 +4596,9 @@ mch_call_shell_fork( #endif if (options & SHELL_COOKED) settmode(TMODE_COOK); // set to normal mode + if (tmode == TMODE_RAW) + // The shell may have messed with the mode, always set it later. + cur_tmode = TMODE_UNKNOWN; if (unix_build_argv(cmd, &argv, &tofree1, &tofree2) == FAIL) goto error; @@ -5924,7 +5964,7 @@ mch_create_pty_channel(job_T *job, jobopt_T *options) void mch_breakcheck(int force) { - if ((curr_tmode == TMODE_RAW || force) + if ((mch_cur_tmode == TMODE_RAW || force) && RealWaitForChar(read_cmd_fd, 0L, NULL, NULL)) fill_input_buf(FALSE); } diff --git a/src/os_unix.h b/src/os_unix.h index 485e057755..9b7337ac19 100644 --- a/src/os_unix.h +++ b/src/os_unix.h @@ -204,6 +204,10 @@ # endif #endif +#ifdef HAVE_FLOCK +# include +#endif + #endif // PROTO #ifdef VMS diff --git a/src/os_vms.c b/src/os_vms.c index 96fbc172f9..b8ad788987 100644 --- a/src/os_vms.c +++ b/src/os_vms.c @@ -112,7 +112,7 @@ vul_item(ITEM *itm, short len, short cod, char *adr, int *ret) } void -mch_settmode(int tmode) +mch_settmode(tmode_T tmode) { int status; diff --git a/src/os_win32.c b/src/os_win32.c index 6b32869756..89c7c5e3aa 100644 --- a/src/os_win32.c +++ b/src/os_win32.c @@ -188,6 +188,7 @@ static int win32_set_archive(char_u *name); static int conpty_working = 0; static int conpty_type = 0; static int conpty_stable = 0; +static int conpty_fix_type = 0; static void vtp_flag_init(); #if !defined(FEAT_GUI_MSWIN) || defined(VIMDLL) @@ -307,6 +308,7 @@ read_console_input( int head; int tail; int i; + static INPUT_RECORD s_irPseudo; if (nLength == -2) return (s_dwMax > 0) ? TRUE : FALSE; @@ -354,6 +356,19 @@ read_console_input( } } + if (s_irCache[s_dwIndex].EventType == KEY_EVENT) + { + if (s_irCache[s_dwIndex].Event.KeyEvent.wRepeatCount > 1) + { + s_irPseudo = s_irCache[s_dwIndex]; + s_irPseudo.Event.KeyEvent.wRepeatCount = 1; + s_irCache[s_dwIndex].Event.KeyEvent.wRepeatCount--; + *lpBuffer = s_irPseudo; + *lpEvents = 1; + return TRUE; + } + } + *lpBuffer = s_irCache[s_dwIndex]; if (!(nLength == -1 || nLength == -2) && ++s_dwIndex >= s_dwMax) s_dwMax = 0; @@ -807,7 +822,7 @@ win32_enable_privilege(LPTSTR lpszPrivilege, BOOL bEnable) #endif /* - * Set "win8_or_later" and fill in "windowsVersion". + * Set "win8_or_later" and fill in "windowsVersion" if possible. */ void PlatformId(void) @@ -821,9 +836,10 @@ PlatformId(void) ovi.dwOSVersionInfoSize = sizeof(ovi); GetVersionEx(&ovi); +#ifdef FEAT_EVAL vim_snprintf(windowsVersion, sizeof(windowsVersion), "%d.%d", (int)ovi.dwMajorVersion, (int)ovi.dwMinorVersion); - +#endif if ((ovi.dwMajorVersion == 6 && ovi.dwMinorVersion >= 2) || ovi.dwMajorVersion > 6) win8_or_later = TRUE; @@ -3585,7 +3601,7 @@ handler_routine( * set the tty in (raw) ? "raw" : "cooked" mode */ void -mch_settmode(int tmode) +mch_settmode(tmode_T tmode) { DWORD cmodein; DWORD cmodeout; @@ -4884,7 +4900,11 @@ mch_call_shell( } if (tmode == TMODE_RAW) + { + // The shell may have messed with the mode, always set it. + cur_tmode = TMODE_UNKNOWN; settmode(TMODE_RAW); // set to raw mode + } // Print the return value, unless "vimrun" was used. if (x != 0 && !(options & SHELL_SILENT) && !emsg_silent @@ -5564,12 +5584,14 @@ 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); + { + DWORD dwDummy; + + FillConsoleOutputCharacter(g_hConOut, ' ', n, coord, &dwDummy); + FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, n, coord, + &dwDummy); + } else { set_console_color_rgb(); @@ -6021,23 +6043,57 @@ write_chars( { COORD coord = g_coord; DWORD written; - DWORD n, cchwritten, cells; + DWORD n, cchwritten; + static DWORD cells; static WCHAR *unicodebuf = NULL; static int unibuflen = 0; - int length; + static int length; int cp = enc_utf8 ? CP_UTF8 : enc_codepage; + static WCHAR *utf8spbuf = NULL; + static int utf8splength; + static DWORD utf8spcells; + static WCHAR **utf8usingbuf = &unicodebuf; - length = MultiByteToWideChar(cp, 0, (LPCSTR)pchBuf, cbToWrite, 0, 0); - if (unicodebuf == NULL || length > unibuflen) + if (cbToWrite != 1 || *pchBuf != ' ' || !enc_utf8) { - vim_free(unicodebuf); - unicodebuf = LALLOC_MULT(WCHAR, length); - unibuflen = length; + utf8usingbuf = &unicodebuf; + do + { + length = MultiByteToWideChar(cp, 0, (LPCSTR)pchBuf, cbToWrite, + unicodebuf, unibuflen); + if (length && length <= unibuflen) + break; + vim_free(unicodebuf); + unicodebuf = length ? LALLOC_MULT(WCHAR, length) : NULL; + unibuflen = unibuflen ? 0 : length; + } while(1); + cells = mb_string2cells(pchBuf, cbToWrite); + } + else // cbToWrite == 1 && *pchBuf == ' ' && enc_utf8 + { + if (utf8usingbuf != &utf8spbuf) + { + if (utf8spbuf == NULL) + { + cells = mb_string2cells((char_u *)" ", 1); + length = MultiByteToWideChar(CP_UTF8, 0, " ", 1, NULL, 0); + utf8spbuf = LALLOC_MULT(WCHAR, length); + if (utf8spbuf != NULL) + { + MultiByteToWideChar(CP_UTF8, 0, " ", 1, utf8spbuf, length); + utf8usingbuf = &utf8spbuf; + utf8splength = length; + utf8spcells = cells; + } + } + else + { + utf8usingbuf = &utf8spbuf; + length = utf8splength; + cells = utf8spcells; + } + } } - MultiByteToWideChar(cp, 0, (LPCSTR)pchBuf, cbToWrite, - unicodebuf, unibuflen); - - cells = mb_string2cells(pchBuf, cbToWrite); if (!USE_VTP) { @@ -6045,14 +6101,14 @@ write_chars( 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, + if (WriteConsoleOutputCharacterW(g_hConOut, *utf8usingbuf, length, coord, &cchwritten) == 0 || cchwritten == 0 || cchwritten == (DWORD)-1) cchwritten = 1; } else { - if (WriteConsoleW(g_hConOut, unicodebuf, length, &cchwritten, + if (WriteConsoleW(g_hConOut, *utf8usingbuf, length, &cchwritten, NULL) == 0 || cchwritten == 0) cchwritten = 1; } @@ -6078,11 +6134,119 @@ write_chars( g_coord.Y++; } - gotoxy(g_coord.X + 1, g_coord.Y + 1); + // Cursor under VTP is always in the correct position, no need to reset. + if (!USE_VTP) + gotoxy(g_coord.X + 1, g_coord.Y + 1); return written; } + static char_u * +get_seq( + int *args, + int *count, + char_u *head) +{ + int argc; + char_u *p; + + if (head == NULL || *head != '\033') + return NULL; + + argc = 0; + p = head; + ++p; + do + { + ++p; + args[argc] = getdigits(&p); + argc += (argc < 15) ? 1 : 0; + } while (*p == ';'); + *count = argc; + + return p; +} + + static char_u * +get_sgr( + int *args, + int *count, + char_u *head) +{ + char_u *p = get_seq(args, count, head); + + return (p && *p == 'm') ? ++p : NULL; +} + +/* + * Pointer to next if SGR (^[[n;2;*;*;*m), NULL otherwise. + */ + static char_u * +sgrn2( + char_u *head, + int n) +{ + int argc; + int args[16]; + char_u *p = get_sgr(args, &argc, head); + + return p && argc == 5 && args[0] == n && args[1] == 2 ? p : NULL; +} + +/* + * Pointer to next if SGR(^[[nm)ESC, NULL otherwise. + */ + static char_u * +sgrnc( + char_u *head, + int n) +{ + int argc; + int args[16]; + char_u *p = get_sgr(args, &argc, head); + + return p && argc == 1 && args[0] == n && (p = skipwhite(p)) && *p == '\033' + ? p : NULL; +} + + static char_u * +skipblank(char_u *q) +{ + char_u *p = q; + + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') + ++p; + return p; +} + +/* + * Pointer to the next if any whitespace that may follow SGR is ESC, otherwise + * NULL. + */ + static char_u * +sgrn2c( + char_u *head, + int n) +{ + char_u *p = sgrn2(head, n); + + return p && *p != NUL && (p = skipblank(p)) && *p == '\033' ? p : NULL; +} + +/* + * If there is only a newline between the sequence immediately following it, + * a pointer to the character following the newline is returned. + * Otherwise NULL. + */ + static char_u * +sgrn2cn( + char_u *head, + int n) +{ + char_u *p = sgrn2(head, n); + + return p && p[0] == 0x0a && p[1] == '\033' ? ++p : NULL; +} /* * mch_write(): write the output buffer to the screen, translating ESC @@ -6109,9 +6273,21 @@ mch_write( // 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"); + int prefix = -1; + char_u ch; + + // While processing a sequence, on rare occasions it seems that another + // sequence may be inserted asynchronously. + if (len < 0) + { + redraw_all_later(CLEAR); + return; + } + + while((ch = s[++prefix])) + if (ch <= 0x1e && !(ch != '\n' && ch != '\r' && ch != '\b' + && ch != '\a' && ch != '\033')) + break; if (p_wd) { @@ -6198,24 +6374,52 @@ mch_write( # endif char_u *p; int arg1 = 0, arg2 = 0, argc = 0, args[16]; + char_u *sp; 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 + if (*(p = get_seq(args, &argc, s)) != 'm') + goto notsgr; + + p = s; + + // Handling frequent optional sequences. Output to the screen + // takes too long, so do not output as much as possible. + + // If resetFG,FG,BG,,BG,FG are connected, the preceding + // resetFG,FG,BG are omitted. + if (sgrn2(sgrn2(sgrn2cn(sgrn2(sgrnc(p, 39), 38), 48), 48), 38)) { - ++p; - args[argc] = getdigits(&p); - argc += (argc < 15) ? 1 : 0; - if (p > s + len) - break; - } while (*p == ';'); - - if (p > s + len) + p = sgrn2(sgrn2(sgrnc(p, 39), 38), 48); + len = len + 1 - (int)(p - s); + s = p; break; + } + // If FG,BG,BG,FG of SGR are connected, the first FG can be + // omitted. + if (sgrn2(sgrn2(sgrn2c((sp = sgrn2(p, 38)), 48), 48), 38)) + p = sp; + + // If FG,BG,FG,BG of SGR are connected, the first FG can be + // omitted. + if (sgrn2(sgrn2(sgrn2c((sp = sgrn2(p, 38)), 48), 38), 48)) + p = sp; + + // If BG,BG of SGR are connected, the first BG can be omitted. + if (sgrn2((sp = sgrn2(p, 48)), 48)) + p = sp; + + // If restoreFG and FG are connected, the restoreFG can be + // omitted. + if (sgrn2((sp = sgrnc(p, 39)), 38)) + p = sp; + + p = get_seq(args, &argc, p); + +notsgr: arg1 = args[0]; arg2 = args[1]; if (*p == 'm') @@ -7274,6 +7478,12 @@ mch_setenv(char *var, char *value, int x UNUSED) */ #define CONPTY_1909_BUILD MAKE_VER(10, 0, 18363) +/* + * Stay ahead of the next update, and when it's done, fix this. + * version ? (2020 update, temporarily use the build number of insider preview) + */ +#define CONPTY_NEXT_UPDATE_BUILD MAKE_VER(10, 0, 19587) + /* * Confirm until this version. Also the logic changes. * insider preview. @@ -7320,6 +7530,9 @@ vtp_flag_init(void) conpty_type = 2; if (ver < CONPTY_FIRST_SUPPORT_BUILD) conpty_type = 1; + + if (ver >= CONPTY_NEXT_UPDATE_BUILD) + conpty_fix_type = 1; } #if !defined(FEAT_GUI_MSWIN) || defined(VIMDLL) || defined(PROTO) @@ -7382,11 +7595,12 @@ vtp_printf( char_u buf[100]; va_list list; DWORD result; + int len; va_start(list, format); - vim_vsnprintf((char *)buf, 100, (char *)format, list); + len = vim_vsnprintf((char *)buf, 100, (char *)format, list); va_end(list); - WriteConsoleA(g_hConOut, buf, (DWORD)STRLEN(buf), &result, NULL); + WriteConsoleA(g_hConOut, buf, (DWORD)len, &result, NULL); return (int)result; } @@ -7400,30 +7614,150 @@ vtp_sgr_bulk( vtp_sgr_bulks(1, args); } +#define FAST256(x) \ + if ((*p-- = "0123456789"[(n = x % 10)]) \ + && x >= 10 && (*p-- = "0123456789"[((m = x % 100) - n) / 10]) \ + && x >= 100 && (*p-- = "012"[((x & 0xff) - m) / 100])); + +#define FAST256CASE(x) \ + case x: \ + FAST256(newargs[x - 1]); + static void vtp_sgr_bulks( int argc, - int *args -) + int *args) { - // 2('\033[') + 4('255.') * 16 + NUL - char_u buf[2 + (4 * 16) + 1]; - char_u *p; - int i; +#define MAXSGR 16 +#define SGRBUFSIZE 2 + 4 * MAXSGR + 1 // '\033[' + SGR + 'm' + char_u buf[SGRBUFSIZE]; + char_u *p; + int in, out; + int newargs[16]; + static int sgrfgr = -1, sgrfgg, sgrfgb; + static int sgrbgr = -1, sgrbgg, sgrbgb; - p = buf; - *p++ = '\033'; - *p++ = '['; - - for (i = 0; i < argc; ++i) + if (argc == 0) { - p += vim_snprintf((char *)p, 4, "%d", args[i] & 0xff); - *p++ = ';'; + sgrfgr = sgrbgr = -1; + vtp_printf("033[m"); + return; + } + + in = out = 0; + while (in < argc) + { + int s = args[in]; + int copylen = 1; + + if (s == 38) + { + if (argc - in >= 5 && args[in + 1] == 2) + { + if (sgrfgr == args[in + 2] && sgrfgg == args[in + 3] + && sgrfgb == args[in + 4]) + { + in += 5; + copylen = 0; + } + else + { + sgrfgr = args[in + 2]; + sgrfgg = args[in + 3]; + sgrfgb = args[in + 4]; + copylen = 5; + } + } + else if (argc - in >= 3 && args[in + 1] == 5) + { + sgrfgr = -1; + copylen = 3; + } + } + else if (s == 48) + { + if (argc - in >= 5 && args[in + 1] == 2) + { + if (sgrbgr == args[in + 2] && sgrbgg == args[in + 3] + && sgrbgb == args[in + 4]) + { + in += 5; + copylen = 0; + } + else + { + sgrbgr = args[in + 2]; + sgrbgg = args[in + 3]; + sgrbgb = args[in + 4]; + copylen = 5; + } + } + else if (argc - in >= 3 && args[in + 1] == 5) + { + sgrbgr = -1; + copylen = 3; + } + } + else if (30 <= s && s <= 39) + sgrfgr = -1; + else if (90 <= s && s <= 97) + sgrfgr = -1; + else if (40 <= s && s <= 49) + sgrbgr = -1; + else if (100 <= s && s <= 107) + sgrbgr = -1; + else if (s == 0) + sgrfgr = sgrbgr = -1; + + while (copylen--) + newargs[out++] = args[in++]; + } + + p = &buf[sizeof(buf) - 1]; + *p-- = 'm'; + + switch (out) + { + int n, m; + DWORD r; + + FAST256CASE(16); + *p-- = ';'; + FAST256CASE(15); + *p-- = ';'; + FAST256CASE(14); + *p-- = ';'; + FAST256CASE(13); + *p-- = ';'; + FAST256CASE(12); + *p-- = ';'; + FAST256CASE(11); + *p-- = ';'; + FAST256CASE(10); + *p-- = ';'; + FAST256CASE(9); + *p-- = ';'; + FAST256CASE(8); + *p-- = ';'; + FAST256CASE(7); + *p-- = ';'; + FAST256CASE(6); + *p-- = ';'; + FAST256CASE(5); + *p-- = ';'; + FAST256CASE(4); + *p-- = ';'; + FAST256CASE(3); + *p-- = ';'; + FAST256CASE(2); + *p-- = ';'; + FAST256CASE(1); + *p-- = '['; + *p = '\033'; + WriteConsoleA(g_hConOut, p, (DWORD)(&buf[SGRBUFSIZE] - p), &r, NULL); + default: + break; } - p--; - *p++ = 'm'; - *p = NUL; - vtp_printf((char *)buf); } # ifdef FEAT_TERMGUICOLORS @@ -7608,6 +7942,12 @@ is_conpty_stable(void) return conpty_stable; } + int +get_conpty_fix_type(void) +{ + return conpty_fix_type; +} + #if !defined(FEAT_GUI_MSWIN) || defined(VIMDLL) || defined(PROTO) void resize_console_buf(void) diff --git a/src/po/af.po b/src/po/af.po index 0b047fc3ef..e19c2c42df 100644 --- a/src/po/af.po +++ b/src/po/af.po @@ -2151,7 +2151,7 @@ msgstr "onbekende 'vimOption'" msgid "keyboard interrupt" msgstr "sleutelbordonderbreking" -msgid "vim error" +msgid "Vim error" msgstr "vim fout" msgid "cannot create buffer/window command: object is being deleted" @@ -2432,8 +2432,8 @@ msgstr "-W \tSkryf alle getikte bevele na l msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\tBewerk geënkripteerde lêers" -msgid "-display \tConnect vim to this particular X-server" -msgstr "-display \tKoppel vim aan hierdie X-bediener" +msgid "-display \tConnect Vim to this particular X-server" +msgstr "-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" @@ -2498,10 +2498,10 @@ msgstr "" "\n" "Parameters deur gvim herken (Athena weergawe):\n" -msgid "-display \tRun vim on " -msgstr "-display \tVoer vim op uit" +msgid "-display \tRun Vim on " +msgstr "-display \tVoer Vim op uit" -msgid "-iconic\t\tStart vim iconified" +msgid "-iconic\t\tStart Vim iconified" msgstr "-iconic\t\tBegin vim as ikoon" msgid "-name \t\tUse resource as if vim was " @@ -2568,8 +2568,8 @@ msgstr "" "\n" "Parameters wat gvim verstaan (GTK+ weergawe):\n" -msgid "-display \tRun vim on (also: --display)" -msgstr "-display \tVoer vim op uit: (ook --display)" +msgid "-display \tRun Vim on (also: --display)" +msgstr "-display \tVoer Vim op uit: (ook --display)" msgid "--role \tSet a unique role to identify the main window" msgstr "--role \tStel 'n unieke rol om die hoofvenster te identifiseer" diff --git a/src/po/ca.po b/src/po/ca.po index 65be8f6d50..5fb5ede67b 100644 --- a/src/po/ca.po +++ b/src/po/ca.po @@ -2760,9 +2760,6 @@ msgstr "opci 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" @@ -3080,7 +3077,7 @@ msgstr "-W