Skip to main content
ALT Linux Bugzilla
– Attachment 13321 Details for
Bug 46325
vis update to 0.8 version
New bug
|
Search
|
[?]
|
Help
Register
|
Log In
[x]
|
Forgot Password
Login:
[x]
|
EN
|
RU
[patch]
patch update to 0.6 => 0.8
vis-0.8.patch (text/plain), 172.95 KB, created by
VikaB
on 2023-05-31 09:09:24 MSK
(
hide
)
Description:
patch update to 0.6 => 0.8
Filename:
MIME Type:
Creator:
VikaB
Created:
2023-05-31 09:09:24 MSK
Size:
172.95 KB
patch
obsolete
>diff -ur vis-0.6/.github/workflows/coverity-scan.yml vis-0.8/.github/workflows/coverity-scan.yml >--- vis-0.6/.github/workflows/coverity-scan.yml 2020-06-07 13:25:20 >+++ vis-0.8/.github/workflows/coverity-scan.yml 2022-11-01 16:50:10 >@@ -24,9 +24,14 @@ > > - name: Download Coverity Build Tool > run: | >- wget -q https://scan.coverity.com/download/cxx/linux64 --post-data "token=$TOKEN&project=martanne/vis" -O cov-analysis-linux64.tar.gz >+ wget -q https://scan.coverity.com/download/cxx/linux64 --post-data "token=$TOKEN&project=martanne/vis" -O coverity_tool.tgz >+ wget -q https://scan.coverity.com/download/cxx/linux64 --post-data "token=$TOKEN&project=martanne/vis&md5=1" -O coverity_tool.md5 >+ if ! (cat coverity_tool.md5; echo " coverity_tool.tgz") | md5sum -c --status; then >+ echo "Download checksum verification failed" >+ exit 1 >+ fi > mkdir cov-analysis-linux64 >- tar xzf cov-analysis-linux64.tar.gz --strip 1 -C cov-analysis-linux64 >+ tar xzf coverity_tool.tgz --strip 1 -C cov-analysis-linux64 > env: > TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }} > >diff -ur vis-0.6/.github/workflows/macos.yml vis-0.8/.github/workflows/macos.yml >--- vis-0.6/.github/workflows/macos.yml 2020-06-07 13:25:20 >+++ vis-0.8/.github/workflows/macos.yml 2022-11-01 16:50:10 >@@ -49,4 +49,10 @@ > env: > CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} > run: | >- bash <(curl -s https://codecov.io/bash) >+ curl -s https://codecov.io/bash > codecov >+ curl -s https://raw.githubusercontent.com/codecov/codecov-bash/master/SHA256SUM > codecov.sha256 >+ if ! sha256sum -c --ignore-missing --status codecov.sha256 ; then >+ echo "Download checksum verification failed" >+ exit 1 >+ fi >+ bash < codecov >diff -ur vis-0.6/.github/workflows/ubuntu.yml vis-0.8/.github/workflows/ubuntu.yml >--- vis-0.6/.github/workflows/ubuntu.yml 2020-06-07 13:25:20 >+++ vis-0.8/.github/workflows/ubuntu.yml 2022-11-01 16:50:10 >@@ -55,4 +55,10 @@ > env: > CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} > run: | >- bash <(curl -s https://codecov.io/bash) >+ curl -s https://codecov.io/bash > codecov >+ curl -s https://raw.githubusercontent.com/codecov/codecov-bash/master/SHA256SUM > codecov.sha256 >+ if ! sha256sum -c --ignore-missing --status codecov.sha256 ; then >+ echo "Download checksum verification failed" >+ exit 1 >+ fi >+ bash < codecov >diff -ur vis-0.6/.github/workflows/windows.yml vis-0.8/.github/workflows/windows.yml >--- vis-0.6/.github/workflows/windows.yml 2020-06-07 13:25:20 >+++ vis-0.8/.github/workflows/windows.yml 2022-11-01 16:50:10 >@@ -21,8 +21,11 @@ > run: | > choco install --no-progress --yes --force --source=cygwin gcc-core,libtool,make,wget,pkg-config > choco install --no-progress --yes --force --source=cygwin lua,lua-devel,lua-lpeg,libncurses-devel >- echo '::add-path::C:\tools\cygwin\bin' > >+ - name: Setup $PATH >+ shell: bash >+ run: echo 'C:\tools\cygwin\bin' >> $GITHUB_PATH >+ > - name: Git configuration > run: | > git config --global core.autocrlf input >@@ -51,4 +54,11 @@ > shell: bash > env: > CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} >- run: bash <(curl -s https://codecov.io/bash) >+ run: | >+ curl -s https://codecov.io/bash > codecov >+ curl -s https://raw.githubusercontent.com/codecov/codecov-bash/master/SHA256SUM > codecov.sha256 >+ if ! sha256sum -c --ignore-missing --status codecov.sha256 ; then >+ echo "Download checksum verification failed" >+ exit 1 >+ fi >+ bash < codecov >diff -ur vis-0.6/.gitignore vis-0.8/.gitignore >--- vis-0.6/.gitignore 2020-06-07 13:25:20 >+++ vis-0.8/.gitignore 2022-11-01 16:50:10 >@@ -12,5 +12,3 @@ > *.gcov > *.html > *.o >-*.swo >-*.swp >diff -ur vis-0.6/Dockerfile vis-0.8/Dockerfile >--- vis-0.6/Dockerfile 2020-06-07 13:25:20 >+++ vis-0.8/Dockerfile 2022-11-01 16:50:10 >@@ -1,5 +1,5 @@ > # Run 'make docker' to build a statically linked vis executable! >-FROM i386/alpine:3.12 >+FROM i386/alpine:3.13 > RUN apk update && apk add --upgrade --no-cache \ > acl-dev \ > acl-static \ >diff -ur vis-0.6/LICENSE vis-0.8/LICENSE >--- vis-0.6/LICENSE 2020-06-07 13:25:20 >+++ vis-0.8/LICENSE 2022-11-01 16:50:10 >@@ -1,6 +1,6 @@ > vis as a whole is licensed under the following standard ISC license: > >- Copyright © 2014-2018 Marc André Tanner, et al. >+ Copyright © 2014-2020 Marc André Tanner, et al. > > Permission to use, copy, modify, and/or distribute this software for any > purpose with or without fee is hereby granted, provided that the above >diff -ur vis-0.6/Makefile vis-0.8/Makefile >--- vis-0.6/Makefile 2020-06-07 13:25:20 >+++ vis-0.8/Makefile 2022-11-01 16:50:10 >@@ -2,10 +2,31 @@ > > REGEX_SRC ?= text-regex.c > >-SRC = array.c buffer.c libutf.c main.c map.c \ >- sam.c text.c text-motions.c text-objects.c text-util.c \ >- ui-terminal.c view.c vis.c vis-lua.c vis-modes.c vis-motions.c \ >- vis-operators.c vis-registers.c vis-marks.c vis-prompt.c vis-text-objects.c $(REGEX_SRC) >+SRC = array.c \ >+ buffer.c \ >+ libutf.c \ >+ main.c \ >+ map.c \ >+ sam.c \ >+ text.c \ >+ text-common.c \ >+ text-io.c \ >+ text-iterator.c \ >+ text-motions.c \ >+ text-objects.c \ >+ text-util.c \ >+ ui-terminal.c \ >+ view.c \ >+ vis.c \ >+ vis-lua.c \ >+ vis-marks.c \ >+ vis-modes.c \ >+ vis-motions.c \ >+ vis-operators.c \ >+ vis-prompt.c \ >+ vis-registers.c \ >+ vis-text-objects.c \ >+ $(REGEX_SRC) > > ELF = vis vis-menu vis-digraph > EXECUTABLES = $(ELF) vis-clipboard vis-complete vis-open >@@ -14,7 +35,7 @@ > > DOCUMENTATION = LICENSE README.md > >-VERSION = v0.6 >+VERSION = 0.8 > > CONFIG_HELP ?= 1 > CONFIG_CURSES ?= 1 >@@ -121,11 +142,19 @@ > [ -e test/Makefile ] || $(MAKE) test-update > @$(MAKE) -C test > >+testclean: >+ @echo cleaning the test artifacts >+ [ ! -e test/Makefile ] || $(MAKE) -C test clean >+ > clean: > @echo cleaning > @rm -f $(ELF) vis-single vis-single-payload.inc vis-*.tar.gz *.gcov *.gcda *.gcno > >-dist: clean >+distclean: clean testclean >+ @echo cleaning build configuration >+ @rm -f config.h config.mk >+ >+dist: distclean > @echo creating dist tarball > @git archive --prefix=vis-${VERSION}/ -o vis-${VERSION}.tar.gz HEAD > >@@ -192,4 +221,4 @@ > @echo removing support files from ${DESTDIR}${SHAREPREFIX}/vis > @rm -rf ${DESTDIR}${SHAREPREFIX}/vis > >-.PHONY: all clean dist install install-strip uninstall debug profile coverage test test-update luadoc luadoc-all luacheck man docker-kill docker docker-clean >+.PHONY: all clean testclean dist distclean install install-strip uninstall debug profile coverage test test-update luadoc luadoc-all luacheck man docker-kill docker docker-clean >diff -ur vis-0.6/README.md vis-0.8/README.md >--- vis-0.6/README.md 2020-06-07 13:25:20 >+++ vis-0.8/README.md 2022-11-01 16:50:10 >@@ -1,10 +1,10 @@ > # Vis - Combining Modal Editing with Structural Regular Expressions > >-[](https://builds.sr.ht/~martanne/vis) >+[](https://builds.sr.ht/~martanne/vis/commits?) > [](https://scan.coverity.com/projects/3939) > [](https://codecov.io/gh/martanne/vis) > [](http://vis.readthedocs.io/en/master/?badge=master) >-[](irc://irc.freenode.net/vis-editor) >+[](ircs://irc.libera.chat:6697/vis-editor) > > Vis aims to be a modern, legacy-free, simple yet efficient editor, > combining the strengths of both vi(m) and sam. >@@ -60,8 +60,8 @@ > $ ./configure && make && sudo make install > > By default the `configure` script will try to auto detect support for >-Lua. See `configure --help` for a list of supported options. You can >-also manually tweak the generated `config.mk` file. >+Lua using `pkg-config(1)`. See `configure --help` for a list of supported >+options. You can also manually tweak the generated `config.mk` file. > > Or simply use one of the > [distribution provided packages](https://github.com/martanne/vis/wiki/Distribution-Packages). >@@ -127,4 +127,4 @@ > > Checkout the [Developer Overview](https://github.com/martanne/vis/wiki/Developer-Overview) > to get started and do not hesitate to ask question in the `#vis-editor` >-IRC channel on freenode. >+IRC channel on libera ([join via your browser](https://web.libera.chat/#vis-editor)). >diff -ur vis-0.6/array.c vis-0.8/array.c >--- vis-0.6/array.c 2020-06-07 13:25:20 >+++ vis-0.8/array.c 2022-11-01 16:50:10 >@@ -11,7 +11,7 @@ > array_init_sized(arr, sizeof(void*)); > } > >-void array_init_from(Array *arr, Array *from) { >+void array_init_from(Array *arr, const Array *from) { > array_init_sized(arr, from->elem_size); > } > >@@ -55,7 +55,7 @@ > memset(arr->items, 0, arr->count * arr->elem_size); > } > >-void *array_get(Array *arr, size_t idx) { >+void *array_get(const Array *arr, size_t idx) { > if (idx >= arr->len) { > errno = EINVAL; > return NULL; >@@ -63,7 +63,7 @@ > return arr->items + (idx * arr->elem_size); > } > >-void *array_get_ptr(Array *arr, size_t idx) { >+void *array_get_ptr(const Array *arr, size_t idx) { > if (arr->elem_size != sizeof(void*)) { > errno = ENOTSUP; > return NULL; >@@ -124,11 +124,11 @@ > return true; > } > >-size_t array_length(Array *arr) { >+size_t array_length(const Array *arr) { > return arr->len; > } > >-size_t array_capacity(Array *arr) { >+size_t array_capacity(const Array *arr) { > return arr->count; > } > >@@ -165,7 +165,7 @@ > return item; > } > >-void *array_peek(Array *arr) { >+void *array_peek(const Array *arr) { > if (arr->len == 0) > return NULL; > return array_get(arr, arr->len - 1); >diff -ur vis-0.6/array.h vis-0.8/array.h >--- vis-0.6/array.h 2020-06-07 13:25:20 >+++ vis-0.8/array.h 2022-11-01 16:50:10 >@@ -44,7 +44,7 @@ > */ > void array_init_sized(Array*, size_t elem_size); > /** Initialize Array by using the same element size as in ``from``. */ >-void array_init_from(Array*, Array *from); >+void array_init_from(Array*, const Array *from); > /** Release storage space. Reinitializes Array object. */ > void array_release(Array*); > /** >@@ -66,7 +66,7 @@ > * of new elements) might invalidate the pointer. > * @endrst > */ >-void *array_get(Array*, size_t idx); >+void *array_get(const Array*, size_t idx); > /** > * Set array element. > * @rst >@@ -76,7 +76,7 @@ > */ > bool array_set(Array*, size_t idx, void *item); > /** Dereference pointer stored in array element. */ >-void *array_get_ptr(Array*, size_t idx); >+void *array_get_ptr(const Array*, size_t idx); > /** Store the address to which ``item`` points to into the array. */ > bool array_set_ptr(Array*, size_t idx, void *item); > /** Add element to the end of the array. */ >@@ -91,16 +91,16 @@ > */ > bool array_remove(Array*, size_t idx); > /** Number of elements currently stored in the array. */ >-size_t array_length(Array*); >+size_t array_length(const Array*); > /** Number of elements which can be stored without enlarging the array. */ >-size_t array_capacity(Array*); >+size_t array_capacity(const Array*); > /** Remove all elements with index greater or equal to ``length``, keep allocated memory. */ > bool array_truncate(Array*, size_t length); > /** > * Change length. > * @rst > * .. note:: Has to be less or equal than the capacity. >- * Newly accesible elements preserve their previous values. >+ * Newly accessible elements preserve their previous values. > * @endrst > */ > bool array_resize(Array*, size_t length); >@@ -128,6 +128,6 @@ > * .. warning:: The same ownership rules as for ``array_get`` apply. > * @endrst > */ >-void *array_peek(Array*); >+void *array_peek(const Array*); > > #endif >diff -ur vis-0.6/buffer.h vis-0.8/buffer.h >--- vis-0.6/buffer.h 2020-06-07 13:25:20 >+++ vis-0.8/buffer.h 2022-11-01 16:50:10 >@@ -44,11 +44,11 @@ > bool buffer_insert0(Buffer*, size_t pos, const char *data); > /** Append further content to the end. */ > bool buffer_append(Buffer*, const void *data, size_t len); >-/** Append NUl-terminated data. */ >+/** Append NUL-terminated data. */ > bool buffer_append0(Buffer*, const char *data); >-/** Insert ``len`` bytes of ``data`` at the begin. */ >+/** Insert ``len`` bytes of ``data`` at the start. */ > bool buffer_prepend(Buffer*, const void *data, size_t len); >-/** Insert NUL-terminated data at the begin. */ >+/** Insert NUL-terminated data at the start. */ > bool buffer_prepend0(Buffer*, const char *data); > /** Set formatted buffer content, ensures NUL termination on success. */ > bool buffer_printf(Buffer*, const char *fmt, ...) __attribute__((format(printf, 2, 3))); >@@ -75,7 +75,7 @@ > /** > * Borrow underlying buffer data. > * @rst >- * .. warning:: The caller is responsible to `free(3)` it. >+ * .. warning:: The caller is responsible to ``free(3)`` it. > * @endrst > */ > char *buffer_move(Buffer*); >diff -ur vis-0.6/config.def.h vis-0.8/config.def.h >--- vis-0.6/config.def.h 2020-06-07 13:25:20 >+++ vis-0.8/config.def.h 2022-11-01 16:50:10 >@@ -45,20 +45,12 @@ > { ",", ACTION(TOTILL_REVERSE) }, > { "+", ALIAS("j^") }, > { "-", ALIAS("k^") }, >- { " ", ALIAS("<Space>") }, >- { "<Space>", ALIAS("l") }, >- { "<Backspace>", ALIAS("h") }, > { "B", ACTION(CURSOR_LONGWORD_START_PREV) }, > { "b", ACTION(CURSOR_WORD_START_PREV) }, >- { "<C-h>", ALIAS("<Backspace>") }, >- { "<C-j>", ALIAS("j") }, >- { "<C-n>", ALIAS("j") }, >- { "<C-p>", ALIAS("k") }, > { "E", ACTION(CURSOR_LONGWORD_END_NEXT) }, > { "e", ACTION(CURSOR_WORD_END_NEXT) }, >- { "<Enter>", ALIAS("j") }, >- { "F", ACTION(TO_LEFT) }, >- { "f", ACTION(TO_RIGHT) }, >+ { "F", ACTION(TO_LINE_LEFT) }, >+ { "f", ACTION(TO_LINE_RIGHT) }, > { "go", ACTION(CURSOR_BYTE) }, > { "gH", ACTION(CURSOR_BYTE_LEFT) }, > { "gL", ACTION(CURSOR_BYTE_RIGHT) }, >@@ -83,8 +75,8 @@ > { "M", ACTION(CURSOR_WINDOW_LINE_MIDDLE) }, > { "n", ACTION(CURSOR_SEARCH_REPEAT_FORWARD) }, > { "N", ACTION(CURSOR_SEARCH_REPEAT_BACKWARD) }, >- { "T", ACTION(TILL_LEFT) }, >- { "t", ACTION(TILL_RIGHT) }, >+ { "T", ACTION(TILL_LINE_LEFT) }, >+ { "t", ACTION(TILL_LINE_RIGHT) }, > { "W", ACTION(CURSOR_LONGWORD_START_NEXT) }, > { "w", ACTION(CURSOR_WORD_START_NEXT) }, > { 0 /* empty last element, array terminator */ }, >@@ -104,7 +96,6 @@ > { "a}", ALIAS("a{") }, > { "ab", ALIAS("a(") }, > { "aB", ALIAS("a{") }, >- { "ae", ACTION(TEXT_OBJECT_ENTIRE_OUTER) }, > { "al", ACTION(TEXT_OBJECT_LINE_OUTER) }, > { "ap", ACTION(TEXT_OBJECT_PARAGRAPH_OUTER) }, > { "as", ACTION(TEXT_OBJECT_SENTENCE) }, >@@ -126,7 +117,6 @@ > { "i}", ALIAS("i{") }, > { "ib", ALIAS("i(") }, > { "iB", ALIAS("i{") }, >- { "ie", ACTION(TEXT_OBJECT_ENTIRE_INNER) }, > { "il", ACTION(TEXT_OBJECT_LINE_INNER) }, > { "ip", ACTION(TEXT_OBJECT_PARAGRAPH) }, > { "is", ACTION(TEXT_OBJECT_SENTENCE) }, >@@ -141,16 +131,8 @@ > { "M", ACTION(SELECTIONS_RESTORE) }, > { "|", ACTION(SELECTIONS_UNION) }, > { "&", ACTION(SELECTIONS_INTERSECT) }, >- { "!", ACTION(SELECTIONS_COMPLEMENT) }, >+ { "~", ACTION(SELECTIONS_COMPLEMENT) }, > { "\\", ACTION(SELECTIONS_MINUS) }, >- { "z|", ACTION(SELECTIONS_COMBINE_UNION) }, >- { "z&", ACTION(SELECTIONS_COMBINE_INTERSECT) }, >- { "z+", ACTION(SELECTIONS_COMBINE_LONGER) }, >- { "z-", ACTION(SELECTIONS_COMBINE_SHORTER) }, >- { "z<", ACTION(SELECTIONS_COMBINE_LEFTMOST) }, >- { "z>", ACTION(SELECTIONS_COMBINE_RIGHTMOST) }, >-// { "-", ACTION(SELECTIONS_ROTATE_LEFT) }, >-// { "+", ACTION(SELECTIONS_ROTATE_RIGHT) }, > { "_", ACTION(SELECTIONS_TRIM) }, > { "<S-Tab>", ACTION(SELECTIONS_ALIGN_INDENT_RIGHT) }, > { "<Tab>", ACTION(SELECTIONS_ALIGN_INDENT_LEFT) }, >@@ -171,7 +153,6 @@ > { "7", ACTION(COUNT) }, > { "8", ACTION(COUNT) }, > { "9", ACTION(COUNT) }, >- { "~", ALIAS("g~") }, > { "=", ALIAS(":|fmt<Enter>") }, > { "<", ACTION(OPERATOR_SHIFT_LEFT) }, > { ">", ACTION(OPERATOR_SHIFT_RIGHT) }, >@@ -203,17 +184,11 @@ > { "<C-j>", ACTION(SELECTIONS_NEW_LINE_BELOW) }, > { "<C-k>", ACTION(SELECTIONS_NEW_LINE_ABOVE) }, > { "<C-l>", ACTION(SELECTIONS_REMOVE_COLUMN_EXCEPT) }, >- { "<C-n>", ACTION(SELECTIONS_MATCH_WORD) }, >+ { "<C-n>", ALIAS("viw") }, > { "<C-p>", ACTION(SELECTIONS_REMOVE_LAST) }, > { "<C-r>", ACTION(REDO) }, > { "<C-u>", ACTION(SELECTIONS_PREV) }, >- { "<C-w><Backspace>", ALIAS("<C-w>k") }, > { "<C-w>c", ALIAS(":q<Enter>") }, >- { "<C-w><C-h>", ALIAS("<C-w>k") }, >- { "<C-w><C-j>", ALIAS("<C-w>j") }, >- { "<C-w><C-k>", ALIAS("<C-w>k") }, >- { "<C-w><C-l>", ALIAS("<C-w>j") }, >- { "<C-w><C-w>", ALIAS("<C-w>j") }, > { "<C-w>h", ALIAS("<C-w>k") }, > { "<C-w>j", ACTION(WINDOW_NEXT) }, > { "<C-w>k", ACTION(WINDOW_PREV) }, >@@ -221,10 +196,8 @@ > { "<C-w>n", ALIAS(":open<Enter>") }, > { "<C-w>s", ALIAS(":split<Enter>") }, > { "<C-w>v", ALIAS(":vsplit<Enter>") }, >- { "<C-w>w", ALIAS("<C-w>j") }, > { "<C-y>", ACTION(WINDOW_SLIDE_DOWN) }, > { "D", ALIAS("d$") }, >- { "<Delete>", ALIAS("x") }, > { "<Escape>", ACTION(MODE_NORMAL_ESCAPE) }, > { "<F1>", ALIAS(":help<Enter>") }, > { "ga", ACTION(UNICODE_INFO) }, >@@ -270,12 +243,11 @@ > { "+", ACTION(SELECTIONS_ROTATE_RIGHT) }, > { "<", ALIAS("<vis-operator-shift-left>gv") }, > { ">", ALIAS("<vis-operator-shift-right>gv") }, >- { "<Backspace>", ALIAS("d") }, >+ { "<C-a>", ACTION(SELECTIONS_NEW_MATCH_ALL) }, > { "<C-b>", ALIAS("<PageUp>") }, > { "<C-c>", ACTION(SELECTIONS_REMOVE_COLUMN) }, > { "<C-d>", ACTION(SELECTIONS_NEXT) }, > { "<C-f>", ALIAS("<PageDown>") }, >- { "<C-h>", ALIAS("<Backspace>") }, > { "<C-j>", ALIAS("<C-d>") }, > { "<C-k>", ALIAS("<C-u>") }, > { "<C-l>", ACTION(SELECTIONS_REMOVE_COLUMN_EXCEPT) }, >@@ -283,7 +255,6 @@ > { "<C-p>", ACTION(SELECTIONS_REMOVE_LAST) }, > { "<C-u>", ACTION(SELECTIONS_PREV) }, > { "<C-x>", ACTION(SELECTIONS_NEW_MATCH_SKIP) }, >- { "<Delete>", ALIAS("<Backspace>") }, > { "<Escape>", ACTION(MODE_VISUAL_ESCAPE) }, > { "I", ACTION(SELECTIONS_NEW_LINES_BEGIN) }, > { "J", ACTION(JOIN_LINES) }, >@@ -314,6 +285,8 @@ > { "<C-u>", ACTION(DELETE_LINE_BEGIN) }, > { "<C-v>", ACTION(INSERT_VERBATIM) }, > { "<C-w>", ACTION(DELETE_WORD_PREV) }, >+ { "<C-e>", ACTION(CURSOR_LINE_END) }, >+ { "<C-a>", ACTION(CURSOR_LINE_START) }, > { "<Delete>", ACTION(DELETE_CHAR_NEXT) }, > { "<Escape>", ACTION(MODE_NORMAL) }, > { 0 /* empty last element, array terminator */ }, >diff -ur vis-0.6/configure vis-0.8/configure >--- vis-0.6/configure 2020-06-07 13:25:20 >+++ vis-0.8/configure 2022-11-01 16:50:10 >@@ -227,6 +227,7 @@ > > case "$OS" in > FreeBSD|DragonFly) CFLAGS_STD="$CFLAGS_STD -D_BSD_SOURCE -D__BSD_VISIBLE=1" ;; >+NetBSD) CFLAGS_STD="$CFLAGS_STD -D_NETBSD_SOURCE" ;; > *BSD) CFLAGS_STD="$CFLAGS_STD -D_BSD_SOURCE" ;; > Darwin) CFLAGS_STD="$CFLAGS_STD -D_DARWIN_C_SOURCE" ;; > AIX) CFLAGS_STD="$CFLAGS_STD -D_ALL_SOURCE" ;; >@@ -309,7 +310,7 @@ > } > EOF > >- for libcurses in ncursesw ncurses libcurses; do >+ for libcurses in ncursesw ncurses curses; do > printf " checking for %s... " "$libcurses" > > if test "$have_pkgconfig" = "yes" ; then >@@ -442,7 +443,7 @@ > } > EOF > >- for liblua in lua lua5.3 lua5.2 lua-5.3 lua-5.2 lua53 lua52; do >+ for liblua in lua lua5.4 lua5.3 lua5.2 lua-5.3 lua-5.2 lua54 lua53 lua52; do > printf " checking for %s... " "$liblua" > > if test "$have_pkgconfig" = "yes" ; then >@@ -474,7 +475,7 @@ > test "$lua" = "yes" -a $CONFIG_LUA -ne 1 && fail "$0: cannot find liblua" > > if test $CONFIG_LUA -eq 1; then >- CFLAGS_LUA="$CFLAGS_LUA -DLUA_COMPAT_5_1 -DLUA_COMPAT_5_2 -DLUA_COMPAT_ALL" >+ CFLAGS_LUA="$CFLAGS_LUA -DLUA_COMPAT_5_1 -DLUA_COMPAT_5_2 -DLUA_COMPAT_5_3 -DLUA_COMPAT_ALL" > fi > fi > >@@ -618,7 +619,7 @@ > } > EOF > >-if $CC $CFLAGS "$tmpc" $LDFLAGS -o "$tmpo" >/dev/null 2>&1; then >+if $CC $CFLAGS $CFLAGS_STD "$tmpc" $LDFLAGS -o "$tmpo" >/dev/null 2>&1; then > HAVE_MEMRCHR=1 > printf "%s\n" "yes" > else >diff -ur vis-0.6/doc/Doxyfile vis-0.8/doc/Doxyfile >--- vis-0.6/doc/Doxyfile 2020-06-07 13:25:20 >+++ vis-0.8/doc/Doxyfile 2022-11-01 16:50:10 >@@ -1,4 +1,4 @@ >-# Doxyfile 1.8.13 >+# Doxyfile 1.8.18 > > # This file describes the settings to be used by the documentation system > # doxygen (www.doxygen.org) for a project. >@@ -17,11 +17,11 @@ > # Project related configuration options > #--------------------------------------------------------------------------- > >-# This tag specifies the encoding used for all characters in the config file >-# that follow. The default is UTF-8 which is also the encoding used for all text >-# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv >-# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv >-# for the list of possible encodings. >+# This tag specifies the encoding used for all characters in the configuration >+# file that follow. The default is UTF-8 which is also the encoding used for all >+# text before the first occurrence of this tag. Doxygen uses libiconv (or the >+# iconv built into libc) for the transcoding. See >+# https://www.gnu.org/software/libiconv/ for the list of possible encodings. > # The default value is: UTF-8. > > DOXYFILE_ENCODING = UTF-8 >@@ -38,7 +38,7 @@ > # could be handy for archiving the generated documentation or if some version > # control system is used. > >-PROJECT_NUMBER = 0.5 >+PROJECT_NUMBER = 0.8 > > # Using the PROJECT_BRIEF tag one can provide an optional one line description > # for a project that appears at the top of each page and should give viewer a >@@ -93,6 +93,14 @@ > > OUTPUT_LANGUAGE = English > >+# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all >+# documentation generated by doxygen is written. Doxygen will use this >+# information to generate all generated output in the proper direction. >+# Possible values are: None, LTR, RTL and Context. >+# The default value is: None. >+ >+OUTPUT_TEXT_DIRECTION = None >+ > # If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member > # descriptions after the members that are listed in the file and class > # documentation (similar to Javadoc). Set to NO to disable this. >@@ -189,6 +197,16 @@ > > JAVADOC_AUTOBRIEF = YES > >+# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line >+# such as >+# /*************** >+# as being the beginning of a Javadoc-style comment "banner". If set to NO, the >+# Javadoc-style will behave just like regular comments and it will not be >+# interpreted by doxygen. >+# The default value is: NO. >+ >+JAVADOC_BANNER = NO >+ > # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first > # line (until the first dot) of a Qt-style comment as the brief description. If > # set to NO, the Qt-style will behave just like regular Qt-style comments (thus >@@ -236,17 +254,16 @@ > # will allow you to put the command \sideeffect (or @sideeffect) in the > # documentation, which will result in a user-defined paragraph with heading > # "Side Effects:". You can put \n's in the value part of an alias to insert >-# newlines. >+# newlines (in the resulting output). You can put ^^ in the value part of an >+# alias to insert a newline as if a physical newline was in the original file. >+# When you need a literal { or } or , in the value part of an alias you have to >+# escape them by means of a backslash (\), this can lead to conflicts with the >+# commands \{ and \} for these it is advised to use the version @{ and @} or use >+# a double escape (\\{ and \\}) > > ALIASES = "rst=\verbatim embed:rst:leading-asterisk" \ > "endrst=\endverbatim" > >-# This tag can be used to specify a number of word-keyword mappings (TCL only). >-# A mapping has the form "name=value". For example adding "class=itcl::class" >-# will allow you to use the command class in the itcl::class meaning. >- >-TCL_SUBST = >- > # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources > # only. Doxygen will then generate output that is more tailored for C. For > # instance, some of the names that are used will be different. The list of all >@@ -275,17 +292,26 @@ > > OPTIMIZE_OUTPUT_VHDL = NO > >+# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice >+# sources only. Doxygen will then generate output that is more tailored for that >+# language. For instance, namespaces will be presented as modules, types will be >+# separated into more groups, etc. >+# The default value is: NO. >+ >+OPTIMIZE_OUTPUT_SLICE = NO >+ > # Doxygen selects the parser to use depending on the extension of the files it > # parses. With this tag you can assign which parser to use for a given > # extension. Doxygen has a built-in mapping, but you can override or extend it > # using this tag. The format is ext=language, where ext is a file extension, and >-# language is one of the parsers supported by doxygen: IDL, Java, Javascript, >-# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: >-# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: >-# Fortran. In the later case the parser tries to guess whether the code is fixed >-# or free formatted code, this is the default for Fortran type files), VHDL. For >-# instance to make doxygen treat .inc files as Fortran files (default is PHP), >-# and .f files as C (default is Fortran), use: inc=Fortran f=C. >+# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, >+# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL, >+# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: >+# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser >+# tries to guess whether the code is fixed or free formatted code, this is the >+# default for Fortran type files). For instance to make doxygen treat .inc files >+# as Fortran files (default is PHP), and .f files as C (default is Fortran), >+# use: inc=Fortran f=C. > # > # Note: For files without extension you can use no_extension as a placeholder. > # >@@ -296,7 +322,7 @@ > > # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments > # according to the Markdown format, which allows for more readable >-# documentation. See http://daringfireball.net/projects/markdown/ for details. >+# documentation. See https://daringfireball.net/projects/markdown/ for details. > # The output of markdown processing is further processed by doxygen, so you can > # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in > # case of backward compatibilities issues. >@@ -308,7 +334,7 @@ > # to that level are automatically included in the table of contents, even if > # they do not have an id attribute. > # Note: This feature currently applies only to Markdown headings. >-# Minimum value: 0, maximum value: 99, default value: 0. >+# Minimum value: 0, maximum value: 99, default value: 5. > # This tag requires that the tag MARKDOWN_SUPPORT is set to YES. > > TOC_INCLUDE_HEADINGS = 0 >@@ -338,7 +364,7 @@ > CPP_CLI_SUPPORT = NO > > # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: >-# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen >+# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen > # will parse them like normal C++ but will assume all classes use public instead > # of private inheritance when no explicit protection keyword is present. > # The default value is: NO. >@@ -444,6 +470,12 @@ > > EXTRACT_PRIVATE = NO > >+# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual >+# methods of a class will be included in the documentation. >+# The default value is: NO. >+ >+EXTRACT_PRIV_VIRTUAL = NO >+ > # If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal > # scope will be included in the documentation. > # The default value is: NO. >@@ -498,8 +530,8 @@ > HIDE_UNDOC_CLASSES = NO > > # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend >-# (class|struct|union) declarations. If set to NO, these declarations will be >-# included in the documentation. >+# declarations. If set to NO, these declarations will be included in the >+# documentation. > # The default value is: NO. > > HIDE_FRIEND_COMPOUNDS = NO >@@ -522,7 +554,7 @@ > # names in lower-case letters. If set to YES, upper-case letters are also > # allowed. This is useful if you have classes or files whose names only differ > # in case and if your file system supports case sensitive file names. Windows >-# and Mac users are advised to set this option to NO. >+# (including Cygwin) ands Mac users are advised to set this option to NO. > # The default value is: system dependent. > > CASE_SENSE_NAMES = YES >@@ -709,7 +741,7 @@ > # The CITE_BIB_FILES tag can be used to specify one or more bib files containing > # the reference definitions. This must be a list of .bib files. The .bib > # extension is automatically appended if omitted. This requires the bibtex tool >-# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. >+# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. > # For LaTeX the style of the bibliography can be controlled using > # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the > # search path. See also \cite for info how to create references. >@@ -754,7 +786,8 @@ > # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that > # are documented, but have no documentation for their parameters or return > # value. If set to NO, doxygen will only warn about wrong or incomplete >-# parameter documentation, but not about the absence of documentation. >+# parameter documentation, but not about the absence of documentation. If >+# EXTRACT_ALL is set to YES then this flag will automatically be disabled. > # The default value is: NO. > > WARN_NO_PARAMDOC = NO >@@ -796,7 +829,7 @@ > # This tag can be used to specify the character encoding of the source files > # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses > # libiconv (or the iconv built into libc) for the transcoding. See the libiconv >-# documentation (see: http://www.gnu.org/software/libiconv) for the list of >+# documentation (see: https://www.gnu.org/software/libiconv/) for the list of > # possible encodings. > # The default value is: UTF-8. > >@@ -813,8 +846,10 @@ > # If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, > # *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, > # *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, >-# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, >-# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf. >+# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment), >+# *.doc (to be provided as doxygen C comment), *.txt (to be provided as doxygen >+# C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, >+# *.vhdl, *.ucf, *.qsf and *.ice. > > FILE_PATTERNS = *.c \ > *.cc \ >@@ -1012,7 +1047,7 @@ > STRIP_CODE_COMMENTS = YES > > # If the REFERENCED_BY_RELATION tag is set to YES then for each documented >-# function all documented functions referencing it will be listed. >+# entity all documented functions referencing it will be listed. > # The default value is: NO. > > REFERENCED_BY_RELATION = NO >@@ -1044,12 +1079,12 @@ > # If the USE_HTAGS tag is set to YES then the references to source code will > # point to the HTML generated by the htags(1) tool instead of doxygen built-in > # source browser. The htags tool is part of GNU's global source tagging system >-# (see http://www.gnu.org/software/global/global.html). You will need version >+# (see https://www.gnu.org/software/global/global.html). You will need version > # 4.8.6 or higher. > # > # To use it do the following: > # - Install the latest version of global >-# - Enable SOURCE_BROWSER and USE_HTAGS in the config file >+# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file > # - Make sure the INPUT points to the root of the source tree > # - Run doxygen as normal > # >@@ -1189,7 +1224,7 @@ > # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen > # will adjust the colors in the style sheet and background images according to > # this color. Hue is specified as an angle on a colorwheel, see >-# http://en.wikipedia.org/wiki/Hue for more information. For instance the value >+# https://en.wikipedia.org/wiki/Hue for more information. For instance the value > # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 > # purple, and 360 is red again. > # Minimum value: 0, maximum value: 359, default value: 220. >@@ -1225,6 +1260,17 @@ > > HTML_TIMESTAMP = NO > >+# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML >+# documentation will contain a main index with vertical navigation menus that >+# are dynamically created via JavaScript. If disabled, the navigation index will >+# consists of multiple levels of tabs that are statically embedded in every HTML >+# page. Disable this option to support browsers that do not have JavaScript, >+# like the Qt help browser. >+# The default value is: YES. >+# This tag requires that the tag GENERATE_HTML is set to YES. >+ >+HTML_DYNAMIC_MENUS = YES >+ > # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML > # documentation will contain sections that can be hidden and shown after the > # page has loaded. >@@ -1248,13 +1294,13 @@ > > # If the GENERATE_DOCSET tag is set to YES, additional index files will be > # generated that can be used as input for Apple's Xcode 3 integrated development >-# environment (see: http://developer.apple.com/tools/xcode/), introduced with >-# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a >+# environment (see: https://developer.apple.com/xcode/), introduced with OSX >+# 10.5 (Leopard). To create a documentation set, doxygen will generate a > # Makefile in the HTML output directory. Running make will produce the docset in > # that directory and running make install will install the docset in > # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at >-# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html >-# for more information. >+# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy >+# genXcode/_index.html for more information. > # The default value is: NO. > # This tag requires that the tag GENERATE_HTML is set to YES. > >@@ -1293,7 +1339,7 @@ > # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three > # additional HTML index files: index.hhp, index.hhc, and index.hhk. The > # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop >-# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on >+# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on > # Windows. > # > # The HTML Help Workshop contains a compiler that can convert all HTML output >@@ -1369,7 +1415,7 @@ > > # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help > # Project output. For more information please see Qt Help Project / Namespace >-# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). >+# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). > # The default value is: org.doxygen.Project. > # This tag requires that the tag GENERATE_QHP is set to YES. > >@@ -1377,7 +1423,7 @@ > > # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt > # Help Project output. For more information please see Qt Help Project / Virtual >-# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- >+# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual- > # folders). > # The default value is: doc. > # This tag requires that the tag GENERATE_QHP is set to YES. >@@ -1386,7 +1432,7 @@ > > # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom > # filter to add. For more information please see Qt Help Project / Custom >-# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- >+# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- > # filters). > # This tag requires that the tag GENERATE_QHP is set to YES. > >@@ -1394,7 +1440,7 @@ > > # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the > # custom filter to add. For more information please see Qt Help Project / Custom >-# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- >+# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- > # filters). > # This tag requires that the tag GENERATE_QHP is set to YES. > >@@ -1402,7 +1448,7 @@ > > # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this > # project's filter section matches. Qt Help Project / Filter Attributes (see: >-# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). >+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). > # This tag requires that the tag GENERATE_QHP is set to YES. > > QHP_SECT_FILTER_ATTRS = >@@ -1486,6 +1532,17 @@ > > EXT_LINKS_IN_WINDOW = NO > >+# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg >+# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see >+# https://inkscape.org) to generate formulas as SVG images instead of PNGs for >+# the HTML output. These images will generally look nicer at scaled resolutions. >+# Possible values are: png The default and svg Looks nicer but requires the >+# pdf2svg tool. >+# The default value is: png. >+# This tag requires that the tag GENERATE_HTML is set to YES. >+ >+HTML_FORMULA_FORMAT = png >+ > # Use this tag to change the font size of LaTeX formulas included as images in > # the HTML documentation. When you change the font size after a successful > # doxygen run you need to manually remove any form_*.png images from the HTML >@@ -1495,7 +1552,7 @@ > > FORMULA_FONTSIZE = 10 > >-# Use the FORMULA_TRANPARENT tag to determine whether or not the images >+# Use the FORMULA_TRANSPARENT tag to determine whether or not the images > # generated for formulas are transparent PNGs. Transparent PNGs are not > # supported properly for IE 6.0, but are supported on all modern browsers. > # >@@ -1506,8 +1563,14 @@ > > FORMULA_TRANSPARENT = YES > >+# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands >+# to create new LaTeX commands to be used in formulas as building blocks. See >+# the section "Including formulas" for details. >+ >+FORMULA_MACROFILE = >+ > # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see >-# http://www.mathjax.org) which uses client side Javascript for the rendering >+# https://www.mathjax.org) which uses client side JavaScript for the rendering > # instead of using pre-rendered bitmaps. Use this if you do not have LaTeX > # installed or if you want to formulas look prettier in the HTML output. When > # enabled you may also need to install MathJax separately and configure the path >@@ -1534,8 +1597,8 @@ > # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax > # Content Delivery Network so you can quickly see the result without installing > # MathJax. However, it is strongly recommended to install a local copy of >-# MathJax from http://www.mathjax.org before deployment. >-# The default value is: http://cdn.mathjax.org/mathjax/latest. >+# MathJax from https://www.mathjax.org before deployment. >+# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2. > # This tag requires that the tag USE_MATHJAX is set to YES. > > MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest >@@ -1577,7 +1640,7 @@ > SEARCHENGINE = YES > > # When the SERVER_BASED_SEARCH tag is enabled the search engine will be >-# implemented using a web server instead of a web client using Javascript. There >+# implemented using a web server instead of a web client using JavaScript. There > # are two flavors of web server based searching depending on the EXTERNAL_SEARCH > # setting. When disabled, doxygen will generate a PHP script for searching and > # an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing >@@ -1596,7 +1659,7 @@ > # > # Doxygen ships with an example indexer (doxyindexer) and search engine > # (doxysearch.cgi) which are based on the open source search engine library >-# Xapian (see: http://xapian.org/). >+# Xapian (see: https://xapian.org/). > # > # See the section "External Indexing and Searching" for details. > # The default value is: NO. >@@ -1609,7 +1672,7 @@ > # > # Doxygen ships with an example indexer (doxyindexer) and search engine > # (doxysearch.cgi) which are based on the open source search engine library >-# Xapian (see: http://xapian.org/). See the section "External Indexing and >+# Xapian (see: https://xapian.org/). See the section "External Indexing and > # Searching" for details. > # This tag requires that the tag SEARCHENGINE is set to YES. > >@@ -1661,21 +1724,35 @@ > # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be > # invoked. > # >-# Note that when enabling USE_PDFLATEX this option is only used for generating >-# bitmaps for formulas in the HTML output, but not in the Makefile that is >-# written to the output directory. >-# The default file is: latex. >+# Note that when not enabling USE_PDFLATEX the default is latex when enabling >+# USE_PDFLATEX the default is pdflatex and when in the later case latex is >+# chosen this is overwritten by pdflatex. For specific output languages the >+# default can have been set differently, this depends on the implementation of >+# the output language. > # This tag requires that the tag GENERATE_LATEX is set to YES. > > LATEX_CMD_NAME = latex > > # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate > # index for LaTeX. >+# Note: This tag is used in the Makefile / make.bat. >+# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file >+# (.tex). > # The default file is: makeindex. > # This tag requires that the tag GENERATE_LATEX is set to YES. > > MAKEINDEX_CMD_NAME = makeindex > >+# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to >+# generate index for LaTeX. In case there is no backslash (\) as first character >+# it will be automatically added in the LaTeX code. >+# Note: This tag is used in the generated output file (.tex). >+# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat. >+# The default value is: makeindex. >+# This tag requires that the tag GENERATE_LATEX is set to YES. >+ >+LATEX_MAKEINDEX_CMD = makeindex >+ > # If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX > # documents. This may be useful for small projects and may help to save some > # trees in general. >@@ -1796,7 +1873,7 @@ > > # The LATEX_BIB_STYLE tag can be used to specify the style to use for the > # bibliography, e.g. plainnat, or ieeetr. See >-# http://en.wikipedia.org/wiki/BibTeX and \cite for more info. >+# https://en.wikipedia.org/wiki/BibTeX and \cite for more info. > # The default value is: plain. > # This tag requires that the tag GENERATE_LATEX is set to YES. > >@@ -1810,6 +1887,14 @@ > > LATEX_TIMESTAMP = NO > >+# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute) >+# path from which the emoji images will be read. If a relative path is entered, >+# it will be relative to the LATEX_OUTPUT directory. If left blank the >+# LATEX_OUTPUT directory will be used. >+# This tag requires that the tag GENERATE_LATEX is set to YES. >+ >+LATEX_EMOJI_DIRECTORY = >+ > #--------------------------------------------------------------------------- > # Configuration options related to the RTF output > #--------------------------------------------------------------------------- >@@ -1849,9 +1934,9 @@ > > RTF_HYPERLINKS = NO > >-# Load stylesheet definitions from file. Syntax is similar to doxygen's config >-# file, i.e. a series of assignments. You only have to provide replacements, >-# missing definitions are set to their default value. >+# Load stylesheet definitions from file. Syntax is similar to doxygen's >+# configuration file, i.e. a series of assignments. You only have to provide >+# replacements, missing definitions are set to their default value. > # > # See also section "Doxygen usage" for information on how to generate the > # default style sheet that doxygen normally uses. >@@ -1860,8 +1945,8 @@ > RTF_STYLESHEET_FILE = > > # Set optional variables used in the generation of an RTF document. Syntax is >-# similar to doxygen's config file. A template extensions file can be generated >-# using doxygen -e rtf extensionFile. >+# similar to doxygen's configuration file. A template extensions file can be >+# generated using doxygen -e rtf extensionFile. > # This tag requires that the tag GENERATE_RTF is set to YES. > > RTF_EXTENSIONS_FILE = >@@ -1947,6 +2032,13 @@ > > XML_PROGRAMLISTING = YES > >+# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include >+# namespace members in file scope as well, matching the HTML output. >+# The default value is: NO. >+# This tag requires that the tag GENERATE_XML is set to YES. >+ >+XML_NS_MEMB_FILE_SCOPE = NO >+ > #--------------------------------------------------------------------------- > # Configuration options related to the DOCBOOK output > #--------------------------------------------------------------------------- >@@ -1979,9 +2071,9 @@ > #--------------------------------------------------------------------------- > > # If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an >-# AutoGen Definitions (see http://autogen.sf.net) file that captures the >-# structure of the code including all documentation. Note that this feature is >-# still experimental and incomplete at the moment. >+# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures >+# the structure of the code including all documentation. Note that this feature >+# is still experimental and incomplete at the moment. > # The default value is: NO. > > GENERATE_AUTOGEN_DEF = NO >@@ -2148,12 +2240,6 @@ > > EXTERNAL_PAGES = YES > >-# The PERL_PATH should be the absolute path and name of the perl script >-# interpreter (i.e. the result of 'which perl'). >-# The default file (with absolute path) is: /usr/bin/perl. >- >-PERL_PATH = /usr/bin/perl >- > #--------------------------------------------------------------------------- > # Configuration options related to the dot tool > #--------------------------------------------------------------------------- >@@ -2166,15 +2252,6 @@ > # The default value is: YES. > > CLASS_DIAGRAMS = YES >- >-# You can define message sequence charts within doxygen comments using the \msc >-# command. Doxygen will then run the mscgen tool (see: >-# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the >-# documentation. The MSCGEN_PATH tag allows you to specify the directory where >-# the mscgen tool resides. If left empty the tool is assumed to be found in the >-# default search path. >- >-MSCGEN_PATH = > > # You can include diagrams made with dia in doxygen documentation. Doxygen will > # then run dia to produce the diagram and insert it in the documentation. The >diff -ur vis-0.6/doc/conf.py vis-0.8/doc/conf.py >--- vis-0.6/doc/conf.py 2020-06-07 13:25:20 >+++ vis-0.8/doc/conf.py 2022-11-01 16:50:10 >@@ -59,7 +59,7 @@ > > # General information about the project. > project = 'Vis Editor' >-copyright = '2017, Marc André Tanner' >+copyright = '2014-2020 Marc André Tanner, et al.' > author = 'Marc André Tanner' > > # The version info for the project you're documenting, acts as replacement for >@@ -67,9 +67,9 @@ > # built documents. > # > # The short X.Y version. >-version = '0.6' >+version = '0.8' > # The full version, including alpha/beta/rc tags. >-release = '0.6' >+release = '0.8' > > # The language for content autogenerated by Sphinx. Refer to documentation > # for a list of supported languages. >@@ -86,10 +86,13 @@ > # The name of the Pygments (syntax highlighting) style to use. > pygments_style = 'sphinx' > >+primary_domain = 'c' >+highlight_language = 'c' >+ > # If true, `todo` and `todoList` produce output, else they produce nothing. > todo_include_todos = False > >-default_role = "any" >+default_role = "c" > > # -- Options for HTML output ---------------------------------------------- > >diff -ur vis-0.6/doc/text.rst vis-0.8/doc/text.rst >--- vis-0.6/doc/text.rst 2020-06-07 13:25:20 >+++ vis-0.8/doc/text.rst 2022-11-01 16:50:10 >@@ -4,7 +4,7 @@ > The core text management data structure which supports efficient > modifications and provides a byte string interface. Text positions > are represented as ``size_t``. Valid addresses are in range ``[0, >-text_size(txt)]``. An invalid position is denoted by `EPOS`. Access to >+text_size(txt)]``. An invalid position is denoted by ``EPOS``. Access to > the non-contigiuos pieces is available by means of an iterator interface > or a copy mechanism. Text revisions are tracked in an history graph. > >@@ -77,7 +77,7 @@ > .. note:: The grapheme cluster boundaries are currently not implemented > according to `UAX#29 rules <http://unicode.org/reports/tr29>`_. > Instead a base character followed by arbitrarily many combining >- character as reported by `wcwidth(3)` are skipped. >+ character as reported by ``wcwidth(3)`` are skipped. > > .. doxygengroup:: iterator_char > :content-only: >@@ -105,7 +105,7 @@ > all marks placed after the modification point. Reverting to an older text > state will hide all affected marks, redoing the changes will restore them. > >-.. warning:: Due to an optimization cached modifications (i.e. no `text_snaphot` >+.. warning:: Due to an optimization cached modifications (i.e. no ``text_snaphot`` > was performed between setting the mark and issuing the changes) might > not adjust mark positions accurately. > >diff -ur vis-0.6/lua/lexers/bash.lua vis-0.8/lua/lexers/bash.lua >--- vis-0.6/lua/lexers/bash.lua 2020-06-07 13:25:20 >+++ vis-0.8/lua/lexers/bash.lua 2022-11-01 16:50:10 >@@ -18,10 +18,18 @@ > local dq_str = l.delimited_range('"') > local ex_str = l.delimited_range('`') > local heredoc = '<<' * P(function(input, index) >- local s, e, _, delimiter = >- input:find('%-?(["\']?)([%a_][%w_]*)%1[\n\r\f;]+', index) >+ local s, e, minus, _, delimiter = >+ input:find('(-?)(["\']?)([%a_][%w_]*)%2[\n\r\f;]+', index) > if s == index and delimiter then >- local _, e = input:find('[\n\r\f]+'..delimiter..'\n', e) >+ -- If the starting delimiter of a here-doc begins with "-", then >+ -- spaces are allowed to come before the closing delimiter. >+ local close_pattern >+ if minus == '-' then >+ close_pattern = '[\n\r\f%s]+'..delimiter..'\n' >+ else >+ close_pattern = '[\n\r\f]+'..delimiter..'\n' >+ end >+ local _, e = input:find(close_pattern, e) > return e and e + 1 or #input + 1 > end > end) >Only in vis-0.8/lua/lexers: gemini.lua >diff -ur vis-0.6/lua/lexers/git-rebase.lua vis-0.8/lua/lexers/git-rebase.lua >--- vis-0.6/lua/lexers/git-rebase.lua 2020-06-07 13:25:20 >+++ vis-0.8/lua/lexers/git-rebase.lua 2022-11-01 16:50:10 >@@ -1,4 +1,4 @@ >--- Copyright 2017 Marc André Tanner >+-- Copyright 2017-2021 Marc André Tanner > -- git-rebase(1) LPeg lexer. > > local l = require('lexer') >@@ -22,6 +22,7 @@ > 'f', 'fixup', > 'x', 'exec', > 'd', 'drop', >+ 'b', 'break', > 'l', 'label', > 't', 'reset', > 'm', 'merge', >Only in vis-0.8/lua/lexers: meson.lua >Only in vis-0.8/lua/lexers: routeros.lua >diff -ur vis-0.6/lua/lexers/strace.lua vis-0.8/lua/lexers/strace.lua >--- vis-0.6/lua/lexers/strace.lua 2020-06-07 13:25:20 >+++ vis-0.8/lua/lexers/strace.lua 2022-11-01 16:50:10 >@@ -1,9 +1,9 @@ >--- Copyright 2017 Marc André Tanner. See LICENSE. >+-- Copyright 2017-2021 Marc André Tanner. See LICENSE. > -- strace(1) output lexer > > local l = require('lexer') > local token, word_match = l.token, l.word_match >-local S = lpeg.S >+local S, B = lpeg.S, lpeg.B > > local M = {_NAME = 'strace'} > >@@ -13,16 +13,18 @@ > local constant = token(l.CONSTANT, (l.upper + '_') * (l.upper + l.digit + '_')^0) > local syscall = token(l.KEYWORD, l.starts_line(l.word)) > local operator = token(l.OPERATOR, S('+-/*%<>~!=^&|?~:;,.()[]{}')) >-local comment = token(l.COMMENT, l.nested_pair('/*', '*/') + ('(' * (l.alpha + ' ')^1 * ')\n')) >-local result = token(l.TYPE, '= ' * l.integer) >+local comment = token(l.COMMENT, l.nested_pair('/*', '*/') + (l.delimited_range('()') * l.newline)) >+local result = token(l.TYPE, B(' = ') * l.integer) >+local identifier = token(l.IDENTIFIER, l.word) > > M._rules = { > {'whitespace', ws}, >- {'keyword', syscall}, >+ {'syscall', syscall}, > {'constant', constant}, > {'string', string}, > {'comment', comment}, >- {'type', result}, >+ {'result', result}, >+ {'identifier', identifier}, > {'number', number}, > {'operator', operator}, > } >Only in vis-0.8/lua/lexers: zig.lua >diff -ur vis-0.6/lua/plugins/complete-filename.lua vis-0.8/lua/plugins/complete-filename.lua >--- vis-0.6/lua/plugins/complete-filename.lua 2020-06-07 13:25:20 >+++ vis-0.8/lua/plugins/complete-filename.lua 2022-11-01 16:50:10 >@@ -13,7 +13,7 @@ > local prefix = file:content(range) > if not prefix then return end > -- Strip leading delimiters for some languages >- i, j = string.find(prefix, "[[(<'\"]+") >+ local _, j = string.find(prefix, "[[(<'\"]+") > if j then prefix = prefix:sub(j + 1) end > local cmd = string.format("vis-complete --file '%s'", prefix:gsub("'", "'\\''")) > local status, out, err = vis:pipe(file, { start = 0, finish = 0 }, cmd) >diff -ur vis-0.6/lua/plugins/filetype.lua vis-0.8/lua/plugins/filetype.lua >--- vis-0.6/lua/plugins/filetype.lua 2020-06-07 13:25:20 >+++ vis-0.8/lua/plugins/filetype.lua 2022-11-01 16:50:10 >@@ -40,7 +40,7 @@ > ext = { "%.awk$" }, > }, > bash = { >- ext = { "%.bash$", "%.csh$", "%.sh$", "%.zsh$" }, >+ ext = { "%.bash$", "%.csh$", "%.sh$", "%.zsh$" ,"^APKBUILD$", "%.ebuild$"}, > mime = { "text/x-shellscript", "application/x-shellscript" }, > }, > batch = { >@@ -149,6 +149,10 @@ > gap = { > ext = { "%.g$", "%.gd$", "%.gi$", "%.gap$" }, > }, >+ gemini = { >+ ext = { "%.gmi" }, >+ mime = { "text/gemini" }, >+ }, > gettext = { > ext = { "%.po$", "%.pot$" }, > }, >@@ -172,7 +176,7 @@ > ext = { "%.go$" }, > }, > groovy = { >- ext = { "%.groovy$", "%.gvy$" }, >+ ext = { "%.groovy$", "%.gvy$", "^Jenkinsfile$" }, > }, > gtkrc = { > ext = { "%.gtkrc$" }, >@@ -204,7 +208,7 @@ > ext = { "%.bsh$", "%.java$" }, > }, > javascript = { >- ext = { "%.js$", "%.jsfl$" }, >+ ext = { "%.cjs$", "%.js$", "%.jsfl$", "%.mjs$", "%.ts$" }, > }, > json = { > ext = { "%.json$" }, >@@ -227,7 +231,7 @@ > ext = { "%.less$" }, > }, > lilypond = { >- ext = { "%.lily$", "%.ly$" }, >+ ext = { "%.ily$", "%.ly$" }, > }, > lisp = { > ext = { "%.cl$", "%.el$", "%.lisp$", "%.lsp$" }, >@@ -246,6 +250,9 @@ > makefile = { > ext = { "%.iface$", "%.mak$", "%.mk$", "GNUmakefile", "makefile", "Makefile" }, > mime = { "text/x-makefile" }, >+ detect = function(_, data) >+ return data:match("^#!/usr/bin/make") >+ end > }, > man = { > ext = { >@@ -258,6 +265,9 @@ > ext = { "%.md$", "%.markdown$" }, > mime = { "text/x-markdown" }, > }, >+ meson = { >+ ext = { "^meson%.build$" }, >+ }, > moonscript = { > ext = { "%.moon$" }, > mime = { "text/x-moon" }, >@@ -343,6 +353,12 @@ > rhtml = { > ext = { "%.erb$", "%.rhtml$" }, > }, >+ routeros = { >+ ext = { "%.rsc" }, >+ detect = function(_, data) >+ return data:match("^#.* by RouterOS") >+ end >+ }, > rstats = { > ext = { "%.R$", "%.Rout$", "%.Rhistory$", "%.Rt$", "Rout.save", "Rout.fail" }, > }, >@@ -363,7 +379,7 @@ > mime = { "text/x-scala" }, > }, > scheme = { >- ext = { "%.sch$", "%.scm$", "%.sld$", "%.sls$", "%.ss$" }, >+ ext = { "%.rkt$", "%.sch$", "%.scm$", "%.sld$", "%.sls$", "%.ss$" }, > }, > smalltalk = { > ext = { "%.changes$", "%.st$", "%.sources$" }, >@@ -381,7 +397,7 @@ > ext = { "%.ddl$", "%.sql$" }, > }, > strace = { >- detect = function(file, data) >+ detect = function(_, data) > return data:match("^execve%(") > end > }, >@@ -403,7 +419,8 @@ > }, > text = { > ext = { "%.txt$" }, >- mime = { "text/plain" }, >+ -- Do *not* list mime "text/plain" here, it is covered below, >+ -- see 'try text lexer as a last resort' > }, > toml = { > ext = { "%.toml$" }, >@@ -422,7 +439,7 @@ > ext = { "%.vcf$", "%.vcard$" }, > }, > verilog = { >- ext = { "%.v$", "%.ver$" }, >+ ext = { "%.v$", "%.ver$", "%.sv$" }, > }, > vhdl = { > ext = { "%.vh$", "%.vhd$", "%.vhdl$" }, >@@ -443,6 +460,9 @@ > ext = { "%.yaml$", "%.yml$" }, > mime = { "text/x-yaml" }, > }, >+ zig = { >+ ext = { "%.zig$" }, >+ }, > } > > vis.events.subscribe(vis.events.WIN_OPEN, function(win) >@@ -484,10 +504,11 @@ > end > > -- run file(1) to determine mime type >+ local mime > if name ~= nil then > local file = io.popen(string.format("file -bL --mime-type -- '%s'", name:gsub("'", "'\\''"))) > if file then >- local mime = file:read('*all') >+ mime = file:read('*all') > file:close() > if mime then > mime = mime:gsub('%s*$', '') >diff -ur vis-0.6/lua/vis.lua vis-0.8/lua/vis.lua >--- vis-0.6/lua/vis.lua 2020-06-07 13:25:20 >+++ vis-0.8/lua/vis.lua 2022-11-01 16:50:10 >@@ -103,7 +103,7 @@ > -- Checks whether a subsequent @{require} call will succeed. > -- @tparam string name the module name to check > -- @treturn bool whether the module was found >-vis.module_exist = function(vis, name) >+vis.module_exist = function(_, name) > for _, searcher in ipairs(package.searchers or package.loaders) do > local loader = searcher(name) > if type(loader) == 'function' then >@@ -151,6 +151,7 @@ > WIN_HIGHLIGHT = "Event::WIN_HIGHLIGHT", -- see @{win_highlight} > WIN_OPEN = "Event::WIN_OPEN", -- see @{win_open} > WIN_STATUS = "Event::WIN_STATUS", -- see @{win_status} >+ TERM_CSI = "Event::TERM_CSI", -- see @{term_csi} > } > > events.file_close = function(...) events.emit(events.FILE_CLOSE, ...) end >@@ -165,6 +166,7 @@ > events.win_highlight = function(...) events.emit(events.WIN_HIGHLIGHT, ...) end > events.win_open = function(...) events.emit(events.WIN_OPEN, ...) end > events.win_status = function(...) events.emit(events.WIN_STATUS, ...) end >+events.term_csi = function(...) events.emit(events.TERM_CSI, ...) end > > local handlers = {} > >diff -ur vis-0.6/main.c vis-0.8/main.c >--- vis-0.6/main.c 2020-06-07 13:25:20 >+++ vis-0.8/main.c 2022-11-01 16:50:10 >@@ -66,8 +66,6 @@ > static const char *selections_remove_column_except(Vis*, const char *keys, const Arg *arg); > /* move to the previous (arg->i < 0) or next (arg->i > 0) selection */ > static const char *selections_navigate(Vis*, const char *keys, const Arg *arg); >-/* select the word the selection is currently over */ >-static const char *selections_match_word(Vis*, const char *keys, const Arg *arg); > /* select the next region matching the current selection */ > static const char *selections_match_next(Vis*, const char *keys, const Arg *arg); > /* clear current selection but select next match */ >@@ -88,14 +86,6 @@ > static const char *selections_complement(Vis*, const char *keys, const Arg *arg); > /* subtract selections from mark */ > static const char *selections_minus(Vis*, const char *keys, const Arg *arg); >-/* pairwise combine selections from mark */ >-static const char *selections_combine(Vis*, const char *keys, const Arg *arg); >-static Filerange combine_union(const Filerange*, const Filerange*); >-static Filerange combine_intersect(const Filerange*, const Filerange*); >-static Filerange combine_longer(const Filerange*, const Filerange*); >-static Filerange combine_shorter(const Filerange*, const Filerange*); >-static Filerange combine_leftmost(const Filerange*, const Filerange*); >-static Filerange combine_rightmost(const Filerange*, const Filerange*); > /* adjust current used count according to keys */ > static const char *count(Vis*, const char *keys, const Arg *arg); > /* move to the count-th line or if not given either to the first (arg->i < 0) >@@ -104,7 +94,7 @@ > /* make the current action use the operator indicated by arg->i */ > static const char *operator(Vis*, const char *keys, const Arg *arg); > /* blocks to read a key and performs movement indicated by arg->i which >- * should be one of VIS_MOVE_{RIGHT,LEFT}_{TO,TILL} */ >+ * should be one of VIS_MOVE_{TO,TILL}_{,LINE}_{RIGHT,LEFT}*/ > static const char *movement_key(Vis*, const char *keys, const Arg *arg); > /* perform the movement as indicated by arg->i */ > static const char *movement(Vis*, const char *keys, const Arg *arg); >@@ -232,8 +222,12 @@ > VIS_ACTION_PROMPT_SEARCH_BACKWARD, > VIS_ACTION_TILL_LEFT, > VIS_ACTION_TILL_RIGHT, >+ VIS_ACTION_TILL_LINE_LEFT, >+ VIS_ACTION_TILL_LINE_RIGHT, > VIS_ACTION_TO_LEFT, > VIS_ACTION_TO_RIGHT, >+ VIS_ACTION_TO_LINE_LEFT, >+ VIS_ACTION_TO_LINE_RIGHT, > VIS_ACTION_REGISTER, > VIS_ACTION_OPERATOR_CHANGE, > VIS_ACTION_OPERATOR_DELETE, >@@ -264,13 +258,13 @@ > VIS_ACTION_WINDOW_SLIDE_DOWN, > VIS_ACTION_PUT_AFTER, > VIS_ACTION_PUT_BEFORE, >- VIS_ACTION_SELECTIONS_MATCH_WORD, > VIS_ACTION_SELECTIONS_NEW_LINE_ABOVE, > VIS_ACTION_SELECTIONS_NEW_LINE_ABOVE_FIRST, > VIS_ACTION_SELECTIONS_NEW_LINE_BELOW, > VIS_ACTION_SELECTIONS_NEW_LINE_BELOW_LAST, > VIS_ACTION_SELECTIONS_NEW_LINES_BEGIN, > VIS_ACTION_SELECTIONS_NEW_LINES_END, >+ VIS_ACTION_SELECTIONS_NEW_MATCH_ALL, > VIS_ACTION_SELECTIONS_NEW_MATCH_NEXT, > VIS_ACTION_SELECTIONS_NEW_MATCH_SKIP, > VIS_ACTION_SELECTIONS_ALIGN, >@@ -291,12 +285,6 @@ > VIS_ACTION_SELECTIONS_INTERSECT, > VIS_ACTION_SELECTIONS_COMPLEMENT, > VIS_ACTION_SELECTIONS_MINUS, >- VIS_ACTION_SELECTIONS_COMBINE_UNION, >- VIS_ACTION_SELECTIONS_COMBINE_INTERSECT, >- VIS_ACTION_SELECTIONS_COMBINE_LONGER, >- VIS_ACTION_SELECTIONS_COMBINE_SHORTER, >- VIS_ACTION_SELECTIONS_COMBINE_LEFTMOST, >- VIS_ACTION_SELECTIONS_COMBINE_RIGHTMOST, > VIS_ACTION_TEXT_OBJECT_WORD_OUTER, > VIS_ACTION_TEXT_OBJECT_WORD_INNER, > VIS_ACTION_TEXT_OBJECT_LONGWORD_OUTER, >@@ -318,8 +306,6 @@ > VIS_ACTION_TEXT_OBJECT_SINGLE_QUOTE_INNER, > VIS_ACTION_TEXT_OBJECT_BACKTICK_OUTER, > VIS_ACTION_TEXT_OBJECT_BACKTICK_INNER, >- VIS_ACTION_TEXT_OBJECT_ENTIRE_OUTER, >- VIS_ACTION_TEXT_OBJECT_ENTIRE_INNER, > VIS_ACTION_TEXT_OBJECT_LINE_OUTER, > VIS_ACTION_TEXT_OBJECT_LINE_INNER, > VIS_ACTION_TEXT_OBJECT_INDENTATION, >@@ -739,23 +725,43 @@ > [VIS_ACTION_TILL_LEFT] = { > "vis-motion-till-left", > VIS_HELP("Till after the occurrence of character to the left") >- movement_key, { .i = VIS_MOVE_LEFT_TILL } >+ movement_key, { .i = VIS_MOVE_TILL_LEFT } > }, > [VIS_ACTION_TILL_RIGHT] = { > "vis-motion-till-right", > VIS_HELP("Till before the occurrence of character to the right") >- movement_key, { .i = VIS_MOVE_RIGHT_TILL } >+ movement_key, { .i = VIS_MOVE_TILL_RIGHT } > }, >+ [VIS_ACTION_TILL_LINE_LEFT] = { >+ "vis-motion-till-line-left", >+ VIS_HELP("Till after the occurrence of character to the left on the current line") >+ movement_key, { .i = VIS_MOVE_TILL_LINE_LEFT } >+ }, >+ [VIS_ACTION_TILL_LINE_RIGHT] = { >+ "vis-motion-till-line-right", >+ VIS_HELP("Till before the occurrence of character to the right on the current line") >+ movement_key, { .i = VIS_MOVE_TILL_LINE_RIGHT } >+ }, > [VIS_ACTION_TO_LEFT] = { > "vis-motion-to-left", > VIS_HELP("To the first occurrence of character to the left") >- movement_key, { .i = VIS_MOVE_LEFT_TO } >+ movement_key, { .i = VIS_MOVE_TO_LEFT } > }, > [VIS_ACTION_TO_RIGHT] = { > "vis-motion-to-right", > VIS_HELP("To the first occurrence of character to the right") >- movement_key, { .i = VIS_MOVE_RIGHT_TO } >+ movement_key, { .i = VIS_MOVE_TO_RIGHT } > }, >+ [VIS_ACTION_TO_LINE_LEFT] = { >+ "vis-motion-to-line-left", >+ VIS_HELP("To the first occurrence of character to the left on the current line") >+ movement_key, { .i = VIS_MOVE_TO_LINE_LEFT } >+ }, >+ [VIS_ACTION_TO_LINE_RIGHT] = { >+ "vis-motion-to-line-right", >+ VIS_HELP("To the first occurrence of character to the right on the current line") >+ movement_key, { .i = VIS_MOVE_TO_LINE_RIGHT } >+ }, > [VIS_ACTION_REGISTER] = { > "vis-register", > VIS_HELP("Use given register for next operator") >@@ -906,11 +912,6 @@ > VIS_HELP("Put text before the cursor") > operator, { .i = VIS_OP_PUT_BEFORE } > }, >- [VIS_ACTION_SELECTIONS_MATCH_WORD] = { >- "vis-selections-select-word", >- VIS_HELP("Select word under cursor") >- selections_match_word, >- }, > [VIS_ACTION_SELECTIONS_NEW_LINE_ABOVE] = { > "vis-selection-new-lines-above", > VIS_HELP("Create a new selection on the line above") >@@ -941,6 +942,11 @@ > VIS_HELP("Create a new selection at the end of every line covered by selection") > operator, { .i = VIS_OP_CURSOR_EOL } > }, >+ [VIS_ACTION_SELECTIONS_NEW_MATCH_ALL] = { >+ "vis-selection-new-match-all", >+ VIS_HELP("Select all regions matching the current selection") >+ selections_match_next, { .b = true } >+ }, > [VIS_ACTION_SELECTIONS_NEW_MATCH_NEXT] = { > "vis-selection-new-match-next", > VIS_HELP("Select the next region matching the current selection") >@@ -1041,36 +1047,6 @@ > VIS_HELP("Subtract selections from mark") > selections_minus > }, >- [VIS_ACTION_SELECTIONS_COMBINE_UNION] = { >- "vis-selections-combine-union", >- VIS_HELP("Pairwise union with selections from mark") >- selections_combine, { .combine = combine_union } >- }, >- [VIS_ACTION_SELECTIONS_COMBINE_INTERSECT] = { >- "vis-selections-combine-intersect", >- VIS_HELP("Pairwise intersect with selections from mark") >- selections_combine, { .combine = combine_intersect } >- }, >- [VIS_ACTION_SELECTIONS_COMBINE_LONGER] = { >- "vis-selections-combine-longer", >- VIS_HELP("Pairwise combine: take longer") >- selections_combine, { .combine = combine_longer } >- }, >- [VIS_ACTION_SELECTIONS_COMBINE_SHORTER] = { >- "vis-selections-combine-shorter", >- VIS_HELP("Pairwise combine: take shorter") >- selections_combine, { .combine = combine_shorter } >- }, >- [VIS_ACTION_SELECTIONS_COMBINE_LEFTMOST] = { >- "vis-selections-combine-leftmost", >- VIS_HELP("Pairwise combine: leftmost") >- selections_combine, { .combine = combine_leftmost } >- }, >- [VIS_ACTION_SELECTIONS_COMBINE_RIGHTMOST] = { >- "vis-selections-combine-rightmost", >- VIS_HELP("Pairwise combine: rightmost") >- selections_combine, { .combine = combine_rightmost } >- }, > [VIS_ACTION_TEXT_OBJECT_WORD_OUTER] = { > "vis-textobject-word-outer", > VIS_HELP("A word leading and trailing whitespace included") >@@ -1176,16 +1152,6 @@ > VIS_HELP("A backtick delimited string (inner variant)") > textobj, { .i = VIS_TEXTOBJECT_INNER_BACKTICK } > }, >- [VIS_ACTION_TEXT_OBJECT_ENTIRE_OUTER] = { >- "vis-textobject-entire-outer", >- VIS_HELP("The whole text content") >- textobj, { .i = VIS_TEXTOBJECT_OUTER_ENTIRE } >- }, >- [VIS_ACTION_TEXT_OBJECT_ENTIRE_INNER] = { >- "vis-textobject-entire-inner", >- VIS_HELP("The whole text content, except for leading and trailing empty lines") >- textobj, { .i = VIS_TEXTOBJECT_INNER_ENTIRE } >- }, > [VIS_ACTION_TEXT_OBJECT_LINE_OUTER] = { > "vis-textobject-line-outer", > VIS_HELP("The whole line") >@@ -1389,19 +1355,7 @@ > return keys; > } > >-static const char *selections_match_word(Vis *vis, const char *keys, const Arg *arg) { >- Text *txt = vis_text(vis); >- View *view = vis_view(vis); >- for (Selection *s = view_selections(view); s; s = view_selections_next(s)) { >- Filerange word = text_object_word(txt, view_cursors_pos(s)); >- if (text_range_valid(&word)) >- view_selections_set(s, &word); >- } >- vis_mode_switch(vis, VIS_MODE_VISUAL); >- return keys; >-} >- >-static const Selection *selection_new_primary(View *view, Filerange *r) { >+static Selection *selection_new(View *view, Filerange *r, bool isprimary) { > Text *txt = view_text(view); > size_t pos = text_char_prev(txt, r->end); > Selection *s = view_selections_new(view, pos); >@@ -1409,41 +1363,11 @@ > return NULL; > view_selections_set(s, r); > view_selections_anchor(s, true); >- view_selections_primary_set(s); >+ if (isprimary) >+ view_selections_primary_set(s); > return s; > } > >-static const char *selections_match_next_literal(Vis *vis, const char *keys, const Arg *arg) { >- Text *txt = vis_text(vis); >- View *view = vis_view(vis); >- Selection *s = view_selections_primary_get(view); >- Filerange sel = view_selections_get(s); >- size_t len = text_range_size(&sel); >- if (!len) >- return keys; >- >- char *buf = text_bytes_alloc0(txt, sel.start, len); >- if (!buf) >- return keys; >- >- size_t start = text_find_next(txt, sel.end, buf); >- Filerange match = text_range_new(start, start+len); >- if (start != sel.end && selection_new_primary(view, &match)) >- goto out; >- >- sel = view_selections_get(view_selections(view)); >- start = text_find_prev(txt, sel.start, buf); >- if (start == sel.start) >- goto out; >- >- match = text_range_new(start, start+len); >- selection_new_primary(view, &match); >- >-out: >- free(buf); >- return keys; >-} >- > static const char *selections_match_next(Vis *vis, const char *keys, const Arg *arg) { > Text *txt = vis_text(vis); > View *view = vis_view(vis); >@@ -1452,24 +1376,45 @@ > if (!text_range_valid(&sel)) > return keys; > >- Filerange word = text_object_word(txt, view_cursors_pos(s)); >- if (!text_range_equal(&sel, &word)) >- return selections_match_next_literal(vis, keys, arg); >+ static bool match_word; > >+ if (view_selections_count(view) == 1) { >+ Filerange word = text_object_word(txt, view_cursors_pos(s)); >+ match_word = text_range_equal(&sel, &word); >+ } >+ >+ Filerange (*find_next)(Text *, size_t, const char *) = text_object_word_find_next; >+ Filerange (*find_prev)(Text *, size_t, const char *) = text_object_word_find_prev; >+ if (!match_word) { >+ find_next = text_object_find_next; >+ find_prev = text_object_find_prev; >+ } >+ > char *buf = text_bytes_alloc0(txt, sel.start, text_range_size(&sel)); > if (!buf) > return keys; > >- word = text_object_word_find_next(txt, sel.end, buf); >- if (text_range_valid(&word) && selection_new_primary(view, &word)) >- goto out; >+ bool match_all = arg->b; >+ Filerange primary = sel; > >- sel = view_selections_get(view_selections(view)); >- word = text_object_word_find_prev(txt, sel.start, buf); >- if (!text_range_valid(&word)) >- goto out; >- selection_new_primary(view, &word); >+ for (;;) { >+ sel = find_next(txt, sel.end, buf); >+ if (!text_range_valid(&sel)) >+ break; >+ if (selection_new(view, &sel, !match_all) && !match_all) >+ goto out; >+ } > >+ sel = primary; >+ >+ for (;;) { >+ sel = find_prev(txt, sel.start, buf); >+ if (!text_range_valid(&sel)) >+ break; >+ if (selection_new(view, &sel, !match_all) && !match_all) >+ break; >+ } >+ > out: > free(buf); > return keys; >@@ -1825,83 +1770,6 @@ > return keys; > } > >-static Filerange combine_union(const Filerange *r1, const Filerange *r2) { >- if (!r1) >- return *r2; >- if (!r2) >- return *r1; >- return text_range_union(r1, r2); >-} >- >-static Filerange combine_intersect(const Filerange *r1, const Filerange *r2) { >- if (!r1 || !r2) >- return text_range_empty(); >- return text_range_intersect(r1, r2); >-} >- >-static Filerange combine_longer(const Filerange *r1, const Filerange *r2) { >- if (!r1) >- return *r2; >- if (!r2) >- return *r1; >- size_t l1 = text_range_size(r1); >- size_t l2 = text_range_size(r2); >- return l1 < l2 ? *r2 : *r1; >-} >- >-static Filerange combine_shorter(const Filerange *r1, const Filerange *r2) { >- if (!r1) >- return *r2; >- if (!r2) >- return *r1; >- size_t l1 = text_range_size(r1); >- size_t l2 = text_range_size(r2); >- return l1 < l2 ? *r1 : *r2; >-} >- >-static Filerange combine_leftmost(const Filerange *r1, const Filerange *r2) { >- if (!r1) >- return *r2; >- if (!r2) >- return *r1; >- return r1->start < r2->start || (r1->start == r2->start && r1->end < r2->end) ? *r1 : *r2; >-} >- >-static Filerange combine_rightmost(const Filerange *r1, const Filerange *r2) { >- if (!r1) >- return *r2; >- if (!r2) >- return *r1; >- return r1->start < r2->start || (r1->start == r2->start && r1->end < r2->end) ? *r2 : *r1; >-} >- >-static const char *selections_combine(Vis *vis, const char *keys, const Arg *arg) { >- Win *win = vis_window(vis); >- View *view = vis_view(vis); >- enum VisMark mark = vis_mark_used(vis); >- Array a = view_selections_get_all(view); >- Array b = vis_mark_get(win, mark); >- Array sel; >- array_init_from(&sel, &a); >- >- Filerange *r1 = array_get(&a, 0), *r2 = array_get(&b, 0); >- for (size_t i = 0, j = 0; r1 || r2; r1 = array_get(&a, ++i), r2 = array_get(&b, ++j)) { >- Filerange new = arg->combine(r1, r2); >- if (text_range_valid(&new)) >- array_add(&sel, &new); >- } >- >- vis_mark_normalize(&sel); >- selections_set(vis, view, &sel); >- vis_cancel(vis); >- >- array_release(&a); >- array_release(&b); >- array_release(&sel); >- >- return keys; >-} >- > static const char *replace(Vis *vis, const char *keys, const Arg *arg) { > if (!keys[0]) { > vis_keymap_disable(vis); >@@ -2227,7 +2095,7 @@ > vis_motion(vis, VIS_MOVE_LINE_BEGIN); > vis_keys_feed(vis, "<vis-motion-line-begin>"); > } >- vis_keys_feed(vis, "<Enter><Up>"); >+ vis_keys_feed(vis, "<Enter><vis-motion-line-up>"); > } > return keys; > } >@@ -2360,6 +2228,7 @@ > .win_close = vis_lua_win_close, > .win_highlight = vis_lua_win_highlight, > .win_status = vis_lua_win_status, >+ .term_csi = vis_lua_term_csi, > }; > > vis = vis_new(ui_term_new(), &event); >diff -ur vis-0.6/man/vis-clipboard.1 vis-0.8/man/vis-clipboard.1 >--- vis-0.6/man/vis-clipboard.1 2020-06-07 13:25:20 >+++ vis-0.8/man/vis-clipboard.1 2022-11-01 16:50:10 >@@ -12,9 +12,11 @@ > .Pp > .Nm vis-clipboard > .Fl -copy >+.Op Fl -selection Ar selection > .Pp > .Nm vis-clipboard > .Fl -paste >+.Op Fl -selection Ar selection > . > .Sh DESCRIPTION > .Nm vis-clipboard >@@ -50,6 +52,8 @@ > .Nm vis-clipboard > reads the content of the system clipboard, > and writes it to standard output. >+.It Fl -selection Ar selection >+specify which selection to use, options are "primary" or "clipboard" > .El > . > .Sh ENVIRONMENT >diff -ur vis-0.6/man/vis.1 vis-0.8/man/vis.1 >--- vis-0.6/man/vis.1 2020-06-07 13:25:20 >+++ vis-0.8/man/vis.1 2022-11-01 16:50:10 >@@ -123,7 +123,7 @@ > .Ss Marks > . > A mark associates a symbolic name to a set of selections. >-A stored selection becomes invalid when its delimiting boundaries changes >+A stored selection becomes invalid when its delimiting boundaries change > in the underlying buffer. > If said changes are later undone the mark becomes valid again. > .Ic m >@@ -769,16 +769,30 @@ > . > .Ss Operators > . >-Operators perform a certain operation an a text range indicated by either a >+Operators perform a certain operation on a text range indicated by either a > motion, a text object or an existing selection. > .Pp >+When used in normal mode, the following operators wait for a motion, putting >+vis into operator pending mode. > .Bl -tag -width XXXXXXXXXX -compact > .It Ic c > change, delete range and enter insert mode > . > .It Ic d >-delete range >+delete, cut range to register > . >+.It Ic < >+shift-left, decrease indent >+. >+.It Ic > >+shift-right, increase indent >+. >+.It Ic y >+yank, copy range to register >+.El >+.Pp >+When used in normal mode, the following actions take effect immediately. >+.Bl -tag -width XXXXXXXXXX -compact > .It Ic = > format, filter range through > .Xr fmt 1 >@@ -789,6 +803,9 @@ > .It Ic gU > make uppercase > . >+.It Ic g~ >+swap case >+. > .It Ic J > join lines, insert spaces in between > . >@@ -796,19 +813,11 @@ > join lines remove any delimiting white spaces > . > .It Ic p >-put, insert register content >+put register content after cursor > . >-.It Ic < >-shift-left, decrease indent >+.It Ic P >+put register content before cursor > . >-.It Ic > >-shift-right, increase indent >-. >-.It Ic ~ >-swap case >-. >-.It Ic y >-yank, copy range to register > .El > . > .Ss Motions >@@ -1026,12 +1035,6 @@ > .It Ic gN > matches the last used search term in backward direction > . >-.It Ic ae >-entire file content >-. >-.It Ic ie >-entire file content except for leading and trailing empty lines >-. > .It Ic al > current line > . >@@ -1103,6 +1106,9 @@ > .It Aq Ic S-Tab > right align selections by inserting spaces > . >+.It Aq Ic C-a >+create new selections everywhere matching current word or selection >+. > .It Aq Ic C-n > create new selection and select next word matching current selection > . >@@ -1160,20 +1166,8 @@ > set intersection > .It Ic \e > set minus >-.It Ic \&! >+.It Ic ~ > set complement >-.It Ic z\&| >-pairwise union >-.It Ic z& >-pairwise intersection >-.It Ic z+ >-pairwise combine, choose longer >-.It Ic z- >-pairwise combine, choose shorter >-.It Ic z< >-pairwise combine, choose leftmost >-.It Ic z> >-pairwise combine, choose rightmost > .El > . > .Sh VI(M) COMMANDS >@@ -1427,6 +1421,8 @@ > WARNING: modifying a memory mapped file in-place will cause data loss. > .It Ic layout Op Do v Dc or Do h Dc > Whether to use vertical or horizontal layout. >+.It Cm ignorecase , Cm ic Op Cm off >+Whether to ignore case when searching. > .El > . > .Sh COMMAND and SEARCH PROMPT >diff -ur vis-0.6/map.c vis-0.8/map.c >--- vis-0.6/map.c 2020-06-07 13:25:20 >+++ vis-0.8/map.c 2022-11-01 16:50:10 >@@ -78,19 +78,6 @@ > return !map_empty(map_prefix(map, prefix)); > } > >-static bool leaf(const char *key, void *value, void *data) >-{ >- int *nodes = data; >- return (*nodes)++ < 1; >-} >- >-bool map_leaf(const Map *map, const char *prefix) >-{ >- int nodes = 0; >- map_iterate(map_prefix(map, prefix), leaf, &nodes); >- return nodes == 1; >-} >- > bool map_put(Map *map, const char *k, const void *value) > { > size_t len = strlen(k); >diff -ur vis-0.6/map.h vis-0.8/map.h >--- vis-0.6/map.h 2020-06-07 13:25:20 >+++ vis-0.8/map.h 2022-11-01 16:50:10 >@@ -35,11 +35,6 @@ > */ > bool map_contains(const Map*, const char *prefix); > /** >- * Check whether the given prefix can be extended to exactly one map element. >- * True iff the prefix map contains exactly one element. >- */ >-bool map_leaf(const Map*, const char *prefix); >-/** > * Store a key value pair in the map. > * @return False if we run out of memory (``errno = ENOMEM``), or if the key > * already appears in the map (``errno = EEXIST``). >diff -ur vis-0.6/sam.c vis-0.8/sam.c >--- vis-0.6/sam.c 2020-06-07 13:25:20 >+++ vis-0.8/sam.c 2022-11-01 16:50:10 >@@ -2,7 +2,7 @@ > * Heavily inspired (and partially based upon) the X11 version of > * Rob Pike's sam text editor originally written for Plan 9. > * >- * Copyright © 2016-2018 Marc André Tanner <mat at brain-dump.org> >+ * Copyright © 2016-2020 Marc André Tanner <mat at brain-dump.org> > * Copyright © 1998 by Lucent Technologies > * > * Permission to use, copy, modify, and distribute this software for any >@@ -23,6 +23,7 @@ > #include <errno.h> > #include <unistd.h> > #include <limits.h> >+#include <fcntl.h> > #include "sam.h" > #include "vis-core.h" > #include "buffer.h" >@@ -144,7 +145,7 @@ > > static const CommandDef cmds[] = { > // name help >- // flags, default command, implemenation >+ // flags, default command, implementation > { > "a", VIS_HELP("Append text after range") > CMD_TEXT, NULL, cmd_append >@@ -277,7 +278,7 @@ > const char *names[3]; /* name and optional alias */ > enum VisOption flags; /* option type, etc. */ > VIS_HELP_DECL(const char *help;) /* short, one line help text */ >- VisOptionFunction *func; /* option handler, NULL for bulitins */ >+ VisOptionFunction *func; /* option handler, NULL for builtins */ > void *context; /* context passed to option handler function */ > } OptionDef; > >@@ -299,6 +300,7 @@ > OPTION_LOAD_METHOD, > OPTION_CHANGE_256COLORS, > OPTION_LAYOUT, >+ OPTION_IGNORECASE, > }; > > static const OptionDef options[] = { >@@ -387,6 +389,11 @@ > VIS_OPTION_TYPE_STRING, > VIS_HELP("Vertical or horizontal window layout") > }, >+ [OPTION_IGNORECASE] = { >+ { "ignorecase", "ic" }, >+ VIS_OPTION_TYPE_BOOL, >+ VIS_HELP("Ignore case when searching") >+ }, > }; > > bool sam_init(Vis *vis) { >@@ -1005,7 +1012,7 @@ > size_t start = range->start, end = range->end, line; > if (sign > 0) { > char c; >- if (start < end && end > 0 && text_byte_get(txt, end-1, &c) && c == '\n') >+ if (start < end && text_byte_get(txt, end-1, &c) && c == '\n') > end--; > line = text_lineno_by_pos(txt, end); > line = text_pos_by_lineno(txt, line + offset); >@@ -1386,14 +1393,13 @@ > Text *txt = win->file->text; > > if (cmd->regex) { >- bool trailing_match = false; >- size_t start = range->start, end = range->end, last_start = EPOS; >+ size_t start = range->start, end = range->end; >+ size_t last_start = argv[0][0] == 'x' ? EPOS : start; > size_t nsub = 1 + text_regex_nsub(cmd->regex); > if (nsub > MAX_REGEX_SUB) > nsub = MAX_REGEX_SUB; > RegexMatch match[MAX_REGEX_SUB]; >- while (start < end || trailing_match) { >- trailing_match = false; >+ while (start <= end) { > char c; > int flags = start > range->start && > text_byte_get(txt, start - 1, &c) && c != '\n' ? >@@ -1406,7 +1412,7 @@ > if (argv[0][0] == 'x') > r = text_range_new(match[0].start, match[0].end); > else >- r = text_range_new(start, match[0].start); >+ r = text_range_new(last_start, match[0].start); > if (match[0].start == match[0].end) { > if (last_start == match[0].start) { > start++; >@@ -1417,16 +1423,17 @@ > * matches the zero-length string immediately after a > * newline. Try filtering out the last such match at EOF. > */ >- if (end == match[0].start && start > range->start) >+ if (end == match[0].start && start > range->start && >+ text_byte_get(txt, end-1, &c) && c == '\n') > break; >+ start = match[0].end + 1; >+ } else { >+ start = match[0].end; > } >- start = match[0].end; >- if (start == end) >- trailing_match = true; > } else { > if (argv[0][0] == 'y') > r = text_range_new(start, end); >- start = end; >+ start = end + 1; > } > > if (text_range_valid(&r)) { >@@ -1435,12 +1442,14 @@ > Register *reg = &vis->registers[VIS_REG_AMPERSAND+i]; > register_put_range(vis, reg, txt, &match[i]); > } >+ last_start = match[0].end; >+ } else { >+ last_start = start; > } > if (simulate) > count++; > else > ret &= sam_execute(vis, win, cmd->cmd, NULL, &r); >- last_start = start; > } > } > } else { >@@ -1670,7 +1679,7 @@ > if (write_entire_file) > *r = text_range_new(0, text_size(text)); > >- TextSave *ctx = text_save_begin(text, path, file->save_method); >+ TextSave *ctx = text_save_begin(text, AT_FDCWD, path, file->save_method); > if (!ctx) { > const char *msg = errno ? strerror(errno) : "try changing `:set savemethod`"; > vis_info_show(vis, "Can't write `%s': %s", path, msg); >Only in vis-0.8: text-common.c >Only in vis-0.8: text-internal.h >Only in vis-0.8: text-io.c >Only in vis-0.8: text-iterator.c >diff -ur vis-0.6/text-motions.c vis-0.8/text-motions.c >--- vis-0.6/text-motions.c 2020-06-07 13:25:20 >+++ vis-0.8/text-motions.c 2022-11-01 16:50:10 >@@ -287,6 +287,8 @@ > size_t text_line_down(Text *txt, size_t pos) { > int width = text_line_width_get(txt, pos); > size_t next = text_line_next(txt, pos); >+ if (next == text_size(txt)) >+ return pos; > return text_line_width_set(txt, next, width); > } > >diff -ur vis-0.6/text-motions.h vis-0.8/text-motions.h >--- vis-0.6/text-motions.h 2020-06-07 13:25:20 >+++ vis-0.8/text-motions.h 2022-11-01 16:50:10 >@@ -1,8 +1,8 @@ > #ifndef TEXT_MOTIONS_H > #define TEXT_MOTIONS_H > >-/* these function all take a position in bytes from the start of the file, >- * perform a certain movement and return the new postion. if the movement >+/* these functions all take a position in bytes from the start of the file, >+ * perform a certain movement and return the new postion. If the movement > * is not possible the original position is returned unchanged. */ > > #include <stddef.h> >@@ -20,7 +20,7 @@ > size_t text_codepoint_prev(Text*, size_t pos); > > /* find the given substring either in forward or backward direction. >- * does not wrap around at file start / end. if no match is found return >+ * does not wrap around at file start / end. If no match is found return > * original position */ > size_t text_find_next(Text*, size_t pos, const char *s); > size_t text_find_prev(Text*, size_t pos, const char *s); >@@ -69,7 +69,7 @@ > /* > * A longword consists of a sequence of non-blank characters, separated with > * white space. TODO?: An empty line is also considered to be a word. >- * This is equivalant to a WORD in vim terminology. >+ * This is equivalent to a WORD in vim terminology. > */ > size_t text_longword_end_next(Text*, size_t pos); > size_t text_longword_end_prev(Text*, size_t pos); >@@ -79,7 +79,7 @@ > * A word consists of a sequence of letters, digits and underscores, or a > * sequence of other non-blank characters, separated with white space. > * TODO?: An empty line is also considered to be a word. >- * This is equivalant to a word (lowercase) in vim terminology. >+ * This is equivalent to a word (lowercase) in vim terminology. > */ > size_t text_word_end_next(Text*, size_t pos); > size_t text_word_end_prev(Text*, size_t pos); >@@ -116,13 +116,13 @@ > size_t text_block_end(Text*, size_t pos); > size_t text_parenthesis_start(Text*, size_t pos); > size_t text_parenthesis_end(Text*, size_t pos); >-/* search coresponding '(', ')', '{', '}', '[', ']', '>', '<', '"', ''' */ >+/* search corresponding '(', ')', '{', '}', '[', ']', '>', '<', '"', ''' */ > size_t text_bracket_match(Text*, size_t pos, const Filerange *limits); > /* same as above but explicitly specify symbols to match */ > size_t text_bracket_match_symbol(Text*, size_t pos, const char *symbols, const Filerange *limits); > > /* search the given regex pattern in either forward or backward direction, >- * starting from pos. does wrap around if no match was found. */ >+ * starting from pos. Does wrap around if no match was found. */ > size_t text_search_forward(Text *txt, size_t pos, Regex *regex); > size_t text_search_backward(Text *txt, size_t pos, Regex *regex); > >diff -ur vis-0.6/text-objects.c vis-0.8/text-objects.c >--- vis-0.6/text-objects.c 2020-06-07 13:25:20 >+++ vis-0.8/text-objects.c 2022-11-01 16:50:10 >@@ -15,19 +15,6 @@ > return text_range_new(0, text_size(txt)); > } > >-Filerange text_object_entire_inner(Text *txt, size_t pos) { >- char c; >- Filerange r = text_object_entire(txt, pos); >- Iterator it = text_iterator_get(txt, r.start); >- if (text_iterator_byte_get(&it, &c) && c == '\n') >- while (text_iterator_byte_next(&it, &c) && c == '\n'); >- r.start = it.pos; >- it = text_iterator_get(txt, r.end); >- while (text_iterator_char_prev(&it, &c) && c == '\n'); >- r.end = it.pos; >- return text_range_linewise(txt, &r); >-} >- > static Filerange text_object_customword(Text *txt, size_t pos, int (*isboundary)(int)) { > Filerange r; > char c, prev = '0', next = '0'; >@@ -40,27 +27,26 @@ > if (space(c)) { > r.start = text_char_next(txt, text_customword_end_prev(txt, pos, isboundary)); > r.end = text_customword_start_next(txt, pos, isboundary); >- } else if (boundary(prev) && boundary(next)) { >- if (boundary(c)) { >- r.start = text_char_next(txt, text_customword_end_prev(txt, pos, isboundary)); >- r.end = text_char_next(txt, text_customword_end_next(txt, pos, isboundary)); >- } else { >- /* on a single character */ >+ } else if (boundary(c)) { >+ if (boundary(prev) && !space(prev)) >+ r.start = text_customword_start_prev(txt, pos, isboundary); >+ else > r.start = pos; >+ >+ if (boundary(next) && !space(next)) >+ r.end = text_char_next(txt, text_customword_end_next(txt, pos, isboundary)); >+ else > r.end = text_char_next(txt, pos); >- } >- } else if (boundary(prev)) { >- /* at start of a word */ >- r.start = pos; >- r.end = text_char_next(txt, text_customword_end_next(txt, pos, isboundary)); >- } else if (boundary(next)) { >- /* at end of a word */ >- r.start = text_customword_start_prev(txt, pos, isboundary); >- r.end = text_char_next(txt, pos); > } else { >- /* in the middle of a word */ >- r.start = text_customword_start_prev(txt, pos, isboundary); >- r.end = text_char_next(txt, text_customword_end_next(txt, pos, isboundary)); >+ if (boundary(prev)) >+ r.start = pos; >+ else >+ r.start = text_customword_start_prev(txt, pos, isboundary); >+ >+ if (boundary(next)) >+ r.end = text_char_next(txt, pos); >+ else >+ r.end = text_char_next(txt, text_customword_end_next(txt, pos, isboundary)); > } > > return r; >@@ -149,6 +135,20 @@ > return text_range_empty(); > } > } >+} >+ >+Filerange text_object_find_next(Text *txt, size_t pos, const char *search) { >+ size_t start = text_find_next(txt, pos, search); >+ if (start == pos) >+ return text_range_empty(); >+ return text_range_new(start, start+strlen(search)); >+} >+ >+Filerange text_object_find_prev(Text *txt, size_t pos, const char *search) { >+ size_t start = text_find_prev(txt, pos, search); >+ if (start == pos) >+ return text_range_empty(); >+ return text_range_new(start, start+strlen(search)); > } > > Filerange text_object_line(Text *txt, size_t pos) { >diff -ur vis-0.6/text-objects.h vis-0.8/text-objects.h >--- vis-0.6/text-objects.h 2020-06-07 13:25:20 >+++ vis-0.8/text-objects.h 2022-11-01 16:50:10 >@@ -1,8 +1,8 @@ > #ifndef TEXT_OBJECTS_H > #define TEXT_OBJECTS_H > >-/* these functions all take a file position. if this position is part of the >- * respective text-object, a corresponding range is returned. if there is no >+/* these functions all take a file position. If this position is part of the >+ * respective text-object, a corresponding range is returned. If there is no > * such text-object at the given location, an empty range is returned. > */ > >@@ -11,16 +11,17 @@ > > /* return range covering the entire text */ > Filerange text_object_entire(Text*, size_t pos); >-/* entire document except leading and trailing empty lines */ >-Filerange text_object_entire_inner(Text*, size_t pos); > /* word which happens to be at pos without any neighbouring white spaces */ > Filerange text_object_word(Text*, size_t pos); >-/* includes trailing white spaces. if at pos happens to be a white space >+/* includes trailing white spaces. If at pos happens to be a white space > * include all neighbouring leading white spaces and the following word. */ > Filerange text_object_word_outer(Text*, size_t pos); >-/* find next occurance of `word' (as word not substring) in forward/backward direction */ >+/* find next occurence of `word' (as word not substring) in forward/backward direction */ > Filerange text_object_word_find_next(Text*, size_t pos, const char *word); > Filerange text_object_word_find_prev(Text*, size_t pos, const char *word); >+/* find next occurence of a literal string (not regex) in forward/backward direction */ >+Filerange text_object_find_next(Text *txt, size_t pos, const char *search); >+Filerange text_object_find_prev(Text *txt, size_t pos, const char *search); > /* same semantics as above but for a longword (i.e. delimited by white spaces) */ > Filerange text_object_longword(Text*, size_t pos); > Filerange text_object_longword_outer(Text*, size_t pos); >@@ -43,7 +44,7 @@ > /* match a search term in either forward or backward direction */ > Filerange text_object_search_forward(Text*, size_t pos, Regex*); > Filerange text_object_search_backward(Text*, size_t pos, Regex*); >-/* match all lines with same indendation level than the current one */ >+/* match all lines with same indentation level as the current one */ > Filerange text_object_indentation(Text*, size_t pos); > > /* extend a range to cover whole lines */ >diff -ur vis-0.6/text.c vis-0.8/text.c >--- vis-0.6/text.c 2020-06-07 13:25:20 >+++ vis-0.8/text.c 2022-11-01 16:50:10 >@@ -1,6 +1,3 @@ >-#ifndef _GNU_SOURCE >-#define _GNU_SOURCE /* memrchr(3) is non-standard */ >-#endif > #include <unistd.h> > #include <stdio.h> > #include <stdlib.h> >@@ -15,48 +12,19 @@ > #include <sys/types.h> > #include <sys/stat.h> > #include <sys/mman.h> >-#if CONFIG_ACL >-#include <sys/acl.h> >-#endif >-#if CONFIG_SELINUX >-#include <selinux/selinux.h> >-#endif > > #include "text.h" > #include "text-util.h" > #include "text-motions.h" > #include "util.h" >+#include "array.h" >+#include "text-internal.h" > >-/* Allocate blocks holding the actual file content in junks of size: */ >-#ifndef BLOCK_SIZE >-#define BLOCK_SIZE (1 << 20) >-#endif >-/* Files smaller than this value are copied on load, larger ones are mmap(2)-ed >- * directely. Hence the former can be truncated, while doing so on the latter >- * results in havoc. */ >-#define BLOCK_MMAP_SIZE (1 << 26) >- >-/* Block holding the file content, either readonly mmap(2)-ed from the original >- * file or heap allocated to store the modifications. >- */ >-typedef struct Block Block; >-struct Block { >- size_t size; /* maximal capacity */ >- size_t len; /* current used length / insertion position */ >- char *data; /* actual data */ >- enum { /* type of allocation */ >- MMAP_ORIG, /* mmap(2)-ed from an external file */ >- MMAP, /* mmap(2)-ed from a temporary file only known to this process */ >- MALLOC, /* heap allocated block using malloc(3) */ >- } type; >- Block *next; /* next junk */ >-}; >- > /* A piece holds a reference (but doesn't itself store) a certain amount of data. > * All active pieces chained together form the whole content of the document. > * At the beginning there exists only one piece, spanning the whole document. > * Upon insertion/deletion new pieces will be created to represent the changes. >- * Generally pieces are never destroyed, but kept around to peform undo/redo >+ * Generally pieces are never destroyed, but kept around to perform undo/redo > * operations. > */ > struct Piece { >@@ -115,8 +83,7 @@ > > /* The main struct holding all information of a given file */ > struct Text { >- Block *block; /* original file content at the time of load operation */ >- Block *blocks; /* all blocks which have been allocated to hold insertion data */ >+ Array blocks; /* blocks which hold text content */ > Piece *pieces; /* all pieces which have been allocated, used to free them */ > Piece *cache; /* most recently modified piece */ > Piece begin, end; /* sentinel nodes which always exists but don't hold any data */ >@@ -129,23 +96,7 @@ > LineCache lines; /* mapping between absolute pos in bytes and logical line breaks */ > }; > >-struct TextSave { /* used to hold context between text_save_{begin,commit} calls */ >- Text *txt; /* text to operate on */ >- char *filename; /* filename to save to as given to text_save_begin */ >- char *tmpname; /* temporary name used for atomic rename(2) */ >- int fd; /* file descriptor to write data to using text_save_write */ >- enum TextSaveMethod type; /* method used to save file */ >-}; >- > /* block management */ >-static Block *block_alloc(Text*, size_t size); >-static Block *block_read(Text*, size_t size, int fd); >-static Block *block_mmap(Text*, size_t size, int fd, off_t offset); >-static void block_free(Block*); >-static bool block_capacity(Block*, size_t len); >-static const char *block_append(Block*, const char *data, size_t len); >-static bool block_insert(Block*, size_t pos, const char *data, size_t len); >-static bool block_delete(Block*, size_t pos, size_t len); > static const char *block_store(Text*, const char *data, size_t len); > /* cache layer */ > static void cache_piece(Text *txt, Piece *p); >@@ -157,7 +108,7 @@ > static void piece_free(Piece *p); > static void piece_init(Piece *p, Piece *prev, Piece *next, const char *data, size_t len); > static Location piece_get_intern(Text *txt, size_t pos); >-static Location piece_get_extern(Text *txt, size_t pos); >+static Location piece_get_extern(const Text *txt, size_t pos); > /* span management */ > static void span_init(Span *span, Piece *start, Piece *end); > static void span_swap(Text *txt, Span *old, Span *new); >@@ -172,145 +123,25 @@ > static size_t lines_skip_forward(Text *txt, size_t pos, size_t lines, size_t *lines_skiped); > static size_t lines_count(Text *txt, size_t pos, size_t len); > >-static ssize_t write_all(int fd, const char *buf, size_t count) { >- size_t rem = count; >- while (rem > 0) { >- ssize_t written = write(fd, buf, rem > INT_MAX ? INT_MAX : rem); >- if (written < 0) { >- if (errno == EAGAIN || errno == EINTR) >- continue; >- return -1; >- } else if (written == 0) { >- break; >- } >- rem -= written; >- buf += written; >- } >- return count - rem; >-} >- >-/* allocate a new block of MAX(size, BLOCK_SIZE) bytes */ >-static Block *block_alloc(Text *txt, size_t size) { >- Block *blk = calloc(1, sizeof *blk); >- if (!blk) >- return NULL; >- if (BLOCK_SIZE > size) >- size = BLOCK_SIZE; >- if (!(blk->data = malloc(size))) { >- free(blk); >- return NULL; >- } >- blk->type = MALLOC; >- blk->size = size; >- blk->next = txt->blocks; >- txt->blocks = blk; >- return blk; >-} >- >-static Block *block_read(Text *txt, size_t size, int fd) { >- Block *blk = block_alloc(txt, size); >- if (!blk) >- return NULL; >- while (size > 0) { >- char data[4096]; >- ssize_t len = read(fd, data, MIN(sizeof(data), size)); >- if (len == -1) { >- txt->blocks = blk->next; >+/* stores the given data in a block, allocates a new one if necessary. Returns >+ * a pointer to the storage location or NULL if allocation failed. */ >+static const char *block_store(Text *txt, const char *data, size_t len) { >+ Block *blk = array_get_ptr(&txt->blocks, array_length(&txt->blocks)-1); >+ if (!blk || !block_capacity(blk, len)) { >+ blk = block_alloc(len); >+ if (!blk) >+ return NULL; >+ if (!array_add_ptr(&txt->blocks, blk)) { > block_free(blk); > return NULL; >- } else if (len == 0) { >- break; >- } else { >- block_append(blk, data, len); >- size -= len; > } > } >- return blk; >-} >- >-static Block *block_mmap(Text *txt, size_t size, int fd, off_t offset) { >- Block *blk = calloc(1, sizeof *blk); >- if (!blk) >- return NULL; >- if (size) { >- blk->data = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, offset); >- if (blk->data == MAP_FAILED) { >- free(blk); >- return NULL; >- } >- } >- blk->type = MMAP_ORIG; >- blk->size = size; >- blk->len = size; >- blk->next = txt->blocks; >- txt->blocks = blk; >- return blk; >-} >- >-static void block_free(Block *blk) { >- if (!blk) >- return; >- if (blk->type == MALLOC) >- free(blk->data); >- else if ((blk->type == MMAP_ORIG || blk->type == MMAP) && blk->data) >- munmap(blk->data, blk->size); >- free(blk); >-} >- >-/* check whether block has enough free space to store len bytes */ >-static bool block_capacity(Block *blk, size_t len) { >- return blk->size - blk->len >= len; >-} >- >-/* append data to block, assumes there is enough space available */ >-static const char *block_append(Block *blk, const char *data, size_t len) { >- char *dest = memcpy(blk->data + blk->len, data, len); >- blk->len += len; >- return dest; >-} >- >-/* stores the given data in a block, allocates a new one if necessary. returns >- * a pointer to the storage location or NULL if allocation failed. */ >-static const char *block_store(Text *txt, const char *data, size_t len) { >- Block *blk = txt->blocks; >- if ((!blk || !block_capacity(blk, len)) && !(blk = block_alloc(txt, len))) >- return NULL; > return block_append(blk, data, len); > } > >-/* insert data into block at an arbitrary position, this should only be used with >- * data of the most recently created piece. */ >-static bool block_insert(Block *blk, size_t pos, const char *data, size_t len) { >- if (pos > blk->len || !block_capacity(blk, len)) >- return false; >- if (blk->len == pos) >- return block_append(blk, data, len); >- char *insert = blk->data + pos; >- memmove(insert + len, insert, blk->len - pos); >- memcpy(insert, data, len); >- blk->len += len; >- return true; >-} >- >-/* delete data from a block at an arbitrary position, this should only be used with >- * data of the most recently created piece. */ >-static bool block_delete(Block *blk, size_t pos, size_t len) { >- size_t end; >- if (!addu(pos, len, &end) || end > blk->len) >- return false; >- if (blk->len == pos) { >- blk->len -= len; >- return true; >- } >- char *delete = blk->data + pos; >- memmove(delete, delete + len, blk->len - pos - len); >- blk->len -= len; >- return true; >-} >- > /* cache the given piece if it is the most recently changed one */ > static void cache_piece(Text *txt, Piece *p) { >- Block *blk = txt->blocks; >+ Block *blk = array_get_ptr(&txt->blocks, array_length(&txt->blocks)-1); > if (!blk || p->data < blk->data || p->data + p->len != blk->data + blk->len) > return; > txt->cache = p; >@@ -318,7 +149,7 @@ > > /* check whether the given piece was the most recently modified one */ > static bool cache_contains(Text *txt, Piece *p) { >- Block *blk = txt->blocks; >+ Block *blk = array_get_ptr(&txt->blocks, array_length(&txt->blocks)-1); > Revision *rev = txt->current_revision; > if (!blk || !txt->cache || txt->cache != p || !rev || !rev->change) > return false; >@@ -336,13 +167,13 @@ > return found && p->data + p->len == blk->data + blk->len; > } > >-/* try to insert a junk of data at a given piece offset. the insertion is only >- * performed if the piece is the most recenetly changed one. the legnth of the >+/* try to insert a chunk of data at a given piece offset. The insertion is only >+ * performed if the piece is the most recently changed one. The length of the > * piece, the span containing it and the whole text is adjusted accordingly */ > static bool cache_insert(Text *txt, Piece *p, size_t off, const char *data, size_t len) { > if (!cache_contains(txt, p)) > return false; >- Block *blk = txt->blocks; >+ Block *blk = array_get_ptr(&txt->blocks, array_length(&txt->blocks)-1); > size_t bufpos = p->data + off - blk->data; > if (!block_insert(blk, bufpos, data, len)) > return false; >@@ -352,14 +183,14 @@ > return true; > } > >-/* try to delete a junk of data at a given piece offset. the deletion is only >- * performed if the piece is the most recenetly changed one and the whole >- * affected range lies within it. the legnth of the piece, the span containing it >+/* try to delete a chunk of data at a given piece offset. The deletion is only >+ * performed if the piece is the most recently changed one and the whole >+ * affected range lies within it. The length of the piece, the span containing it > * and the whole text is adjusted accordingly */ > static bool cache_delete(Text *txt, Piece *p, size_t off, size_t len) { > if (!cache_contains(txt, p)) > return false; >- Block *blk = txt->blocks; >+ Block *blk = array_get_ptr(&txt->blocks, array_length(&txt->blocks)-1); > size_t end; > size_t bufpos = p->data + off - blk->data; > if (!addu(off, len, &end) || end > p->len || !block_delete(blk, bufpos, len)) >@@ -485,9 +316,9 @@ > p->len = len; > } > >-/* returns the piece holding the text at byte offset pos. if pos happens to >- * be at a piece boundry i.e. the first byte of a piece then the previous piece >- * to the left is returned with an offset of piece->len. this is convenient for >+/* returns the piece holding the text at byte offset pos. If pos happens to >+ * be at a piece boundary i.e. the first byte of a piece then the previous piece >+ * to the left is returned with an offset of piece->len. This is convenient for > * modifications to the piece chain where both pieces (the returned one and the > * one following it) are needed, but unsuitable as a public interface. > * >@@ -504,12 +335,12 @@ > return (Location){ 0 }; > } > >-/* similiar to piece_get_intern but usable as a public API. returns the piece >- * holding the text at byte offset pos. never returns a sentinel piece. >+/* similiar to piece_get_intern but usable as a public API. Returns the piece >+ * holding the text at byte offset pos. Never returns a sentinel piece. > * it pos is the end of file (== text_size()) and the file is not empty then > * the last piece holding data is returned. > */ >-static Location piece_get_extern(Text *txt, size_t pos) { >+static Location piece_get_extern(const Text *txt, size_t pos) { > size_t cur = 0; > Piece *p; > >@@ -616,8 +447,8 @@ > span_init(&c->new, new, new); > span_init(&c->old, NULL, NULL); > } else { >- /* insert into middle of an existing piece, therfore split the old >- * piece. that is we have 3 new pieces one containing the content >+ /* insert into middle of an existing piece, therefore split the old >+ * piece. That is we have 3 new pieces one containing the content > * before the insertion point then one holding the newly inserted > * text and one holding the content after the insertion point. > */ >@@ -639,37 +470,6 @@ > return true; > } > >-static bool text_vprintf(Text *txt, size_t pos, const char *format, va_list ap) { >- va_list ap_save; >- va_copy(ap_save, ap); >- int len = vsnprintf(NULL, 0, format, ap); >- if (len == -1) { >- va_end(ap_save); >- return false; >- } >- char *buf = malloc(len+1); >- bool ret = buf && (vsnprintf(buf, len+1, format, ap_save) == len) && text_insert(txt, pos, buf, len); >- free(buf); >- va_end(ap_save); >- return ret; >-} >- >-bool text_appendf(Text *txt, const char *format, ...) { >- va_list ap; >- va_start(ap, format); >- bool ret = text_vprintf(txt, text_size(txt), format, ap); >- va_end(ap); >- return ret; >-} >- >-bool text_printf(Text *txt, size_t pos, const char *format, ...) { >- va_list ap; >- va_start(ap, format); >- bool ret = text_vprintf(txt, pos, format, ap); >- va_end(ap); >- return ret; >-} >- > static size_t revision_undo(Text *txt, Revision *rev) { > size_t pos = EPOS; > for (Change *c = rev->change; c; c = c->next) { >@@ -781,383 +581,35 @@ > return history_traverse_to(txt, rev); > } > >-time_t text_state(Text *txt) { >+time_t text_state(const Text *txt) { > return txt->history->time; > } > >-static bool preserve_acl(int src, int dest) { >-#if CONFIG_ACL >- acl_t acl = acl_get_fd(src); >- if (!acl) >- return errno == ENOTSUP ? true : false; >- if (acl_set_fd(dest, acl) == -1) { >- acl_free(acl); >- return false; >- } >- acl_free(acl); >-#endif /* CONFIG_ACL */ >- return true; >-} >- >-static bool preserve_selinux_context(int src, int dest) { >-#if CONFIG_SELINUX >- char *context = NULL; >- if (!is_selinux_enabled()) >- return true; >- if (fgetfilecon(src, &context) == -1) >- return errno == ENOTSUP ? true : false; >- if (fsetfilecon(dest, context) == -1) { >- freecon(context); >- return false; >- } >- freecon(context); >-#endif /* CONFIG_SELINUX */ >- return true; >-} >- >-/* Create a new file named `.filename.vis.XXXXXX` (where `XXXXXX` is a >- * randomly generated, unique suffix) and try to preserve all important >- * meta data. After the file content has been written to this temporary >- * file, text_save_commit_atomic will atomically move it to its final >- * (possibly already existing) destination using rename(2). >- * >- * This approach does not work if: >- * >- * - the file is a symbolic link >- * - the file is a hard link >- * - file ownership can not be preserved >- * - file group can not be preserved >- * - directory permissions do not allow creation of a new file >- * - POSXI ACL can not be preserved (if enabled) >- * - SELinux security context can not be preserved (if enabled) >- */ >-static bool text_save_begin_atomic(TextSave *ctx) { >- int oldfd, saved_errno; >- if ((oldfd = open(ctx->filename, O_RDONLY)) == -1 && errno != ENOENT) >- goto err; >- struct stat oldmeta = { 0 }; >- if (oldfd != -1 && lstat(ctx->filename, &oldmeta) == -1) >- goto err; >- if (oldfd != -1) { >- if (S_ISLNK(oldmeta.st_mode)) /* symbolic link */ >- goto err; >- if (oldmeta.st_nlink > 1) /* hard link */ >- goto err; >- } >- >- char suffix[] = ".vis.XXXXXX"; >- size_t len = strlen(ctx->filename) + sizeof("./.") + sizeof(suffix); >- char *dir = strdup(ctx->filename); >- char *base = strdup(ctx->filename); >- >- if (!(ctx->tmpname = malloc(len)) || !dir || !base) { >- free(dir); >- free(base); >- goto err; >- } >- >- snprintf(ctx->tmpname, len, "%s/.%s%s", dirname(dir), basename(base), suffix); >- free(dir); >- free(base); >- >- if ((ctx->fd = mkstemp(ctx->tmpname)) == -1) >- goto err; >- >- if (oldfd == -1) { >- mode_t mask = umask(0); >- umask(mask); >- if (fchmod(ctx->fd, 0666 & ~mask) == -1) >- goto err; >- } else { >- if (fchmod(ctx->fd, oldmeta.st_mode) == -1) >- goto err; >- if (!preserve_acl(oldfd, ctx->fd) || !preserve_selinux_context(oldfd, ctx->fd)) >- goto err; >- /* change owner if necessary */ >- if (oldmeta.st_uid != getuid() && fchown(ctx->fd, oldmeta.st_uid, (uid_t)-1) == -1) >- goto err; >- /* change group if necessary, in case of failure some editors reset >- * the group permissions to the same as for others */ >- if (oldmeta.st_gid != getgid() && fchown(ctx->fd, (uid_t)-1, oldmeta.st_gid) == -1) >- goto err; >- close(oldfd); >- } >- >- ctx->type = TEXT_SAVE_ATOMIC; >- return true; >-err: >- saved_errno = errno; >- if (oldfd != -1) >- close(oldfd); >- if (ctx->fd != -1) >- close(ctx->fd); >- ctx->fd = -1; >- free(ctx->tmpname); >- ctx->tmpname = NULL; >- errno = saved_errno; >- return false; >-} >- >-static bool text_save_commit_atomic(TextSave *ctx) { >- if (fsync(ctx->fd) == -1) >- return false; >- >- struct stat meta = { 0 }; >- if (fstat(ctx->fd, &meta) == -1) >- return false; >- >- bool close_failed = (close(ctx->fd) == -1); >- ctx->fd = -1; >- if (close_failed) >- return false; >- >- if (rename(ctx->tmpname, ctx->filename) == -1) >- return false; >- >- free(ctx->tmpname); >- ctx->tmpname = NULL; >- >- int dir = open(dirname(ctx->filename), O_DIRECTORY|O_RDONLY); >- if (dir == -1) >- return false; >- >- if (fsync(dir) == -1 && errno != EINVAL) { >- close(dir); >- return false; >- } >- >- if (close(dir) == -1) >- return false; >- >- if (meta.st_mtime) >- ctx->txt->info = meta; >- return true; >-} >- >-static bool text_save_begin_inplace(TextSave *ctx) { >- Text *txt = ctx->txt; >- struct stat meta = { 0 }; >- int newfd = -1, saved_errno; >- if ((ctx->fd = open(ctx->filename, O_CREAT|O_WRONLY, 0666)) == -1) >- goto err; >- if (fstat(ctx->fd, &meta) == -1) >- goto err; >- if (meta.st_dev == txt->info.st_dev && meta.st_ino == txt->info.st_ino && >- txt->block && txt->block->type == MMAP_ORIG && txt->block->size) { >- /* The file we are going to overwrite is currently mmap-ed from >- * text_load, therefore we copy the mmap-ed block to a temporary >- * file and remap it at the same position such that all pointers >- * from the various pieces are still valid. >- */ >- size_t size = txt->block->size; >- char tmpname[32] = "/tmp/vis-XXXXXX"; >- newfd = mkstemp(tmpname); >- if (newfd == -1) >- goto err; >- if (unlink(tmpname) == -1) >- goto err; >- ssize_t written = write_all(newfd, txt->block->data, size); >- if (written == -1 || (size_t)written != size) >- goto err; >- if (munmap(txt->block->data, size) == -1) >- goto err; >- >- void *data = mmap(txt->block->data, size, PROT_READ, MAP_SHARED, newfd, 0); >- if (data == MAP_FAILED) >- goto err; >- if (data != txt->block->data) { >- munmap(data, size); >- goto err; >- } >- bool close_failed = (close(newfd) == -1); >- newfd = -1; >- if (close_failed) >- goto err; >- txt->block->data = data; >- txt->block->type = MMAP; >- newfd = -1; >- } >- /* overwrite the existing file content, if something goes wrong >- * here we are screwed, TODO: make a backup before? */ >- if (ftruncate(ctx->fd, 0) == -1) >- goto err; >- ctx->type = TEXT_SAVE_INPLACE; >- return true; >-err: >- saved_errno = errno; >- if (newfd != -1) >- close(newfd); >- if (ctx->fd != -1) >- close(ctx->fd); >- ctx->fd = -1; >- errno = saved_errno; >- return false; >-} >- >-static bool text_save_commit_inplace(TextSave *ctx) { >- if (fsync(ctx->fd) == -1) >- return false; >- struct stat meta = { 0 }; >- if (fstat(ctx->fd, &meta) == -1) >- return false; >- if (close(ctx->fd) == -1) >- return false; >- ctx->txt->info = meta; >- return true; >-} >- >-TextSave *text_save_begin(Text *txt, const char *filename, enum TextSaveMethod type) { >- if (!filename) >- return NULL; >- TextSave *ctx = calloc(1, sizeof *ctx); >- if (!ctx) >- return NULL; >- ctx->txt = txt; >- ctx->fd = -1; >- if (!(ctx->filename = strdup(filename))) >- goto err; >- errno = 0; >- if ((type == TEXT_SAVE_AUTO || type == TEXT_SAVE_ATOMIC) && text_save_begin_atomic(ctx)) >- return ctx; >- if (errno == ENOSPC) >- goto err; >- if ((type == TEXT_SAVE_AUTO || type == TEXT_SAVE_INPLACE) && text_save_begin_inplace(ctx)) >- return ctx; >-err: >- text_save_cancel(ctx); >- return NULL; >-} >- >-bool text_save_commit(TextSave *ctx) { >- if (!ctx) >- return true; >- bool ret; >- Text *txt = ctx->txt; >- switch (ctx->type) { >- case TEXT_SAVE_ATOMIC: >- ret = text_save_commit_atomic(ctx); >- break; >- case TEXT_SAVE_INPLACE: >- ret = text_save_commit_inplace(ctx); >- break; >- default: >- ret = false; >- break; >- } >- >- if (ret) { >- txt->saved_revision = txt->history; >- text_snapshot(txt); >- } >- text_save_cancel(ctx); >- return ret; >-} >- >-void text_save_cancel(TextSave *ctx) { >- if (!ctx) >- return; >- int saved_errno = errno; >- if (ctx->fd != -1) >- close(ctx->fd); >- if (ctx->tmpname && ctx->tmpname[0]) >- unlink(ctx->tmpname); >- free(ctx->tmpname); >- free(ctx->filename); >- free(ctx); >- errno = saved_errno; >-} >- >-/* First try to save the file atomically using rename(2) if this does not >- * work overwrite the file in place. However if something goes wrong during >- * this overwrite the original file is permanently damaged. >- */ >-bool text_save(Text *txt, const char *filename) { >- return text_save_method(txt, filename, TEXT_SAVE_AUTO); >-} >- >-bool text_save_method(Text *txt, const char *filename, enum TextSaveMethod method) { >- if (!filename) { >- txt->saved_revision = txt->history; >- text_snapshot(txt); >- return true; >- } >- TextSave *ctx = text_save_begin(txt, filename, method); >- if (!ctx) >- return false; >- Filerange range = (Filerange){ .start = 0, .end = text_size(txt) }; >- ssize_t written = text_save_write_range(ctx, &range); >- if (written == -1 || (size_t)written != text_range_size(&range)) { >- text_save_cancel(ctx); >- return false; >- } >- return text_save_commit(ctx); >-} >- >-ssize_t text_save_write_range(TextSave *ctx, Filerange *range) { >- return text_write_range(ctx->txt, range, ctx->fd); >-} >- >-ssize_t text_write(Text *txt, int fd) { >- Filerange r = (Filerange){ .start = 0, .end = text_size(txt) }; >- return text_write_range(txt, &r, fd); >-} >- >-ssize_t text_write_range(Text *txt, Filerange *range, int fd) { >- size_t size = text_range_size(range), rem = size; >- for (Iterator it = text_iterator_get(txt, range->start); >- rem > 0 && text_iterator_valid(&it); >- text_iterator_next(&it)) { >- size_t prem = it.end - it.text; >- if (prem > rem) >- prem = rem; >- ssize_t written = write_all(fd, it.text, prem); >- if (written == -1) >- return -1; >- rem -= written; >- if ((size_t)written != prem) >- break; >- } >- return size - rem; >-} >- >-Text *text_load(const char *filename) { >- return text_load_method(filename, TEXT_LOAD_AUTO); >-} >- >-Text *text_load_method(const char *filename, enum TextLoadMethod method) { >- int fd = -1; >- size_t size = 0; >+Text *text_loadat_method(int dirfd, const char *filename, enum TextLoadMethod method) { > Text *txt = calloc(1, sizeof *txt); > if (!txt) > return NULL; > Piece *p = piece_alloc(txt); > if (!p) > goto out; >+ Block *block = NULL; >+ array_init(&txt->blocks); > lineno_cache_invalidate(&txt->lines); > if (filename) { >- if ((fd = open(filename, O_RDONLY)) == -1) >+ errno = 0; >+ block = block_load(dirfd, filename, method, &txt->info); >+ if (!block && errno) > goto out; >- if (fstat(fd, &txt->info) == -1) >+ if (block && !array_add_ptr(&txt->blocks, block)) { >+ block_free(block); > goto out; >- if (!S_ISREG(txt->info.st_mode)) { >- errno = S_ISDIR(txt->info.st_mode) ? EISDIR : ENOTSUP; >- goto out; > } >- // XXX: use lseek(fd, 0, SEEK_END); instead? >- size = txt->info.st_size; >- if (size > 0) { >- if (method == TEXT_LOAD_READ || (method == TEXT_LOAD_AUTO && size < BLOCK_MMAP_SIZE)) >- txt->block = block_read(txt, size, fd); >- else >- txt->block = block_mmap(txt, size, fd, 0); >- if (!txt->block) >- goto out; >- piece_init(p, &txt->begin, &txt->end, txt->block->data, txt->block->len); >- } > } > >- if (size == 0) >+ if (!block) > piece_init(p, &txt->begin, &txt->end, "\0", 0); >+ else >+ piece_init(p, &txt->begin, &txt->end, block->data, block->len); > > piece_init(&txt->begin, NULL, p, NULL, 0); > piece_init(&txt->end, p, NULL, NULL, 0); >@@ -1167,22 +619,32 @@ > text_snapshot(txt); > txt->saved_revision = txt->history; > >- if (fd != -1) >- close(fd); > return txt; > out: >- if (fd != -1) >- close(fd); > text_free(txt); > return NULL; > } > >-struct stat text_stat(Text *txt) { >+struct stat text_stat(const Text *txt) { > return txt->info; > } > >+void text_saved(Text *txt, struct stat *meta) { >+ if (meta) >+ txt->info = *meta; >+ txt->saved_revision = txt->history; >+ text_snapshot(txt); >+} >+ >+Block *text_block_mmaped(Text *txt) { >+ Block *block = array_get_ptr(&txt->blocks, 0); >+ if (block && block->type == BLOCK_TYPE_MMAP_ORIG && block->size) >+ return block; >+ return NULL; >+} >+ > /* A delete operation can either start/stop midway through a piece or at >- * a boundry. In the former case a new piece is created to represent the >+ * a boundary. In the former case a new piece is created to represent the > * remaining text before/after the modification point. > * > * /-+ --> +---------+ --> +-----+ --> +-----+ --> +-\ >@@ -1221,7 +683,7 @@ > size_t cur; /* how much has already been deleted */ > > if (off == p->len) { >- /* deletion starts at a piece boundry */ >+ /* deletion starts at a piece boundary */ > cur = 0; > before = p; > start = p->next; >@@ -1242,7 +704,7 @@ > } > > if (cur == len) { >- /* deletion stops at a piece boundry */ >+ /* deletion stops at a piece boundary */ > end = p; > after = p->next; > } else { >@@ -1278,7 +740,7 @@ > return true; > } > >-bool text_delete_range(Text *txt, Filerange *r) { >+bool text_delete_range(Text *txt, const Filerange *r) { > if (!text_range_valid(r)) > return false; > return text_delete(txt, r->start, text_range_size(r)); >@@ -1286,11 +748,12 @@ > > /* preserve the current text content such that it can be restored by > * means of undo/redo operations */ >-void text_snapshot(Text *txt) { >+bool text_snapshot(Text *txt) { > if (txt->current_revision) > txt->last_revision = txt->current_revision; > txt->current_revision = NULL; > txt->cache = NULL; >+ return true; > } > > >@@ -1313,265 +776,79 @@ > piece_free(p); > } > >- for (Block *next, *blk = txt->blocks; blk; blk = next) { >- next = blk->next; >- block_free(blk); >- } >+ for (size_t i = 0, len = array_length(&txt->blocks); i < len; i++) >+ block_free(array_get_ptr(&txt->blocks, i)); >+ array_release(&txt->blocks); > > free(txt); > } > >-bool text_modified(Text *txt) { >+bool text_modified(const Text *txt) { > return txt->saved_revision != txt->history; > } > >-bool text_mmaped(Text *txt, const char *ptr) { >+bool text_mmaped(const Text *txt, const char *ptr) { > uintptr_t addr = (uintptr_t)ptr; >- for (Block *blk = txt->blocks; blk; blk = blk->next) { >- if ((blk->type == MMAP_ORIG || blk->type == MMAP) && >+ for (size_t i = 0, len = array_length(&txt->blocks); i < len; i++) { >+ Block *blk = array_get_ptr(&txt->blocks, i); >+ if ((blk->type == BLOCK_TYPE_MMAP_ORIG || blk->type == BLOCK_TYPE_MMAP) && > (uintptr_t)(blk->data) <= addr && addr < (uintptr_t)(blk->data + blk->size)) > return true; > } > return false; > } > >-static bool text_iterator_init(Iterator *it, size_t pos, Piece *p, size_t off) { >- Iterator iter = (Iterator){ >+static bool iterator_init(Iterator *it, size_t pos, Piece *p, size_t off) { >+ *it = (Iterator){ > .pos = pos, > .piece = p, > .start = p ? p->data : NULL, >- .end = p ? p->data + p->len : NULL, >- .text = p ? p->data + off : NULL, >+ .end = p && p->data ? p->data + p->len : NULL, >+ .text = p && p->data ? p->data + off : NULL, > }; >- *it = iter; > return text_iterator_valid(it); > } > >-Iterator text_iterator_get(Text *txt, size_t pos) { >- Iterator it; >+bool text_iterator_init(const Text *txt, Iterator *it, size_t pos) { > Location loc = piece_get_extern(txt, pos); >- text_iterator_init(&it, pos, loc.piece, loc.off); >- return it; >+ return iterator_init(it, pos, loc.piece, loc.off); > } > >-bool text_iterator_byte_get(Iterator *it, char *b) { >- if (text_iterator_valid(it)) { >- if (it->start <= it->text && it->text < it->end) { >- *b = *it->text; >- return true; >- } else if (it->pos == it->piece->text->size) { /* EOF */ >- *b = '\0'; >- return true; >- } >- } >- return false; >+Iterator text_iterator_get(const Text *txt, size_t pos) { >+ Iterator it; >+ text_iterator_init(txt, &it, pos); >+ return it; > } > > bool text_iterator_next(Iterator *it) { > size_t rem = it->end - it->text; >- return text_iterator_init(it, it->pos+rem, it->piece ? it->piece->next : NULL, 0); >+ return iterator_init(it, it->pos+rem, it->piece ? it->piece->next : NULL, 0); > } > > bool text_iterator_prev(Iterator *it) { > size_t off = it->text - it->start; > size_t len = it->piece && it->piece->prev ? it->piece->prev->len : 0; >- return text_iterator_init(it, it->pos-off, it->piece ? it->piece->prev : NULL, len); >+ return iterator_init(it, it->pos-off, it->piece ? it->piece->prev : NULL, len); > } > >+const Text *text_iterator_text(const Iterator *it) { >+ return it->piece ? it->piece->text : NULL; >+} >+ > bool text_iterator_valid(const Iterator *it) { > /* filter out sentinel nodes */ > return it->piece && it->piece->text; > } > >-bool text_iterator_byte_next(Iterator *it, char *b) { >- if (!it->piece || !it->piece->next) >- return false; >- bool eof = true; >- if (it->text < it->end) { >- it->text++; >- it->pos++; >- eof = false; >- } else if (!it->piece->prev) { >- eof = false; >- } >- >- while (it->text == it->end) { >- if (!text_iterator_next(it)) { >- if (eof) >- return false; >- if (b) >- *b = '\0'; >- return text_iterator_prev(it); >- } >- } >- >- if (b) >- *b = *it->text; >- return true; >+bool text_iterator_has_next(const Iterator *it) { >+ return it->piece && it->piece->next; > } > >-bool text_iterator_byte_prev(Iterator *it, char *b) { >- if (!it->piece || !it->piece->prev) >- return false; >- bool eof = !it->piece->next; >- while (it->text == it->start) { >- if (!text_iterator_prev(it)) { >- if (!eof) >- return false; >- if (b) >- *b = '\0'; >- return text_iterator_next(it); >- } >- } >- >- --it->text; >- --it->pos; >- >- if (b) >- *b = *it->text; >- return true; >+bool text_iterator_has_prev(const Iterator *it) { >+ return it->piece && it->piece->prev; > } > >-bool text_iterator_byte_find_prev(Iterator *it, char b) { >- while (it->text) { >- const char *match = memrchr(it->start, b, it->text - it->start); >- if (match) { >- it->pos -= it->text - match; >- it->text = match; >- return true; >- } >- text_iterator_prev(it); >- } >- text_iterator_next(it); >- return false; >-} >- >-bool text_iterator_byte_find_next(Iterator *it, char b) { >- while (it->text) { >- const char *match = memchr(it->text, b, it->end - it->text); >- if (match) { >- it->pos += match - it->text; >- it->text = match; >- return true; >- } >- text_iterator_next(it); >- } >- text_iterator_prev(it); >- return false; >-} >- >-bool text_iterator_codepoint_next(Iterator *it, char *c) { >- while (text_iterator_byte_next(it, NULL)) { >- if (ISUTF8(*it->text)) { >- if (c) >- *c = *it->text; >- return true; >- } >- } >- return false; >-} >- >-bool text_iterator_codepoint_prev(Iterator *it, char *c) { >- while (text_iterator_byte_prev(it, NULL)) { >- if (ISUTF8(*it->text)) { >- if (c) >- *c = *it->text; >- return true; >- } >- } >- return false; >-} >- >-bool text_iterator_char_next(Iterator *it, char *c) { >- if (!text_iterator_codepoint_next(it, c)) >- return false; >- mbstate_t ps = { 0 }; >- for (;;) { >- char buf[MB_LEN_MAX]; >- size_t len = text_bytes_get(it->piece->text, it->pos, sizeof buf, buf); >- wchar_t wc; >- size_t wclen = mbrtowc(&wc, buf, len, &ps); >- if (wclen == (size_t)-1 && errno == EILSEQ) { >- return true; >- } else if (wclen == (size_t)-2) { >- return false; >- } else if (wclen == 0) { >- return true; >- } else { >- int width = wcwidth(wc); >- if (width != 0) >- return true; >- if (!text_iterator_codepoint_next(it, c)) >- return false; >- } >- } >- return true; >-} >- >-bool text_iterator_char_prev(Iterator *it, char *c) { >- if (!text_iterator_codepoint_prev(it, c)) >- return false; >- for (;;) { >- char buf[MB_LEN_MAX]; >- size_t len = text_bytes_get(it->piece->text, it->pos, sizeof buf, buf); >- wchar_t wc; >- mbstate_t ps = { 0 }; >- size_t wclen = mbrtowc(&wc, buf, len, &ps); >- if (wclen == (size_t)-1 && errno == EILSEQ) { >- return true; >- } else if (wclen == (size_t)-2) { >- return false; >- } else if (wclen == 0) { >- return true; >- } else { >- int width = wcwidth(wc); >- if (width != 0) >- return true; >- if (!text_iterator_codepoint_prev(it, c)) >- return false; >- } >- } >- return true; >-} >- >-bool text_byte_get(Text *txt, size_t pos, char *byte) { >- return text_bytes_get(txt, pos, 1, byte); >-} >- >-size_t text_bytes_get(Text *txt, size_t pos, size_t len, char *buf) { >- if (!buf) >- return 0; >- char *cur = buf; >- size_t rem = len; >- for (Iterator it = text_iterator_get(txt, pos); >- text_iterator_valid(&it); >- text_iterator_next(&it)) { >- if (rem == 0) >- break; >- size_t piece_len = it.end - it.text; >- if (piece_len > rem) >- piece_len = rem; >- if (piece_len) { >- memcpy(cur, it.text, piece_len); >- cur += piece_len; >- rem -= piece_len; >- } >- } >- return len - rem; >-} >- >-char *text_bytes_alloc0(Text *txt, size_t pos, size_t len) { >- if (len == SIZE_MAX) >- return NULL; >- char *buf = malloc(len+1); >- if (!buf) >- return NULL; >- len = text_bytes_get(txt, pos, len, buf); >- buf[len] = '\0'; >- return buf; >-} >- >-size_t text_size(Text *txt) { >+size_t text_size(const Text *txt) { > return txt->size; > } > >@@ -1680,7 +957,7 @@ > return (Mark)(loc.piece->data + loc.off); > } > >-size_t text_mark_get(Text *txt, Mark mark) { >+size_t text_mark_get(const Text *txt, Mark mark) { > size_t cur = 0; > > if (mark == EMARK) >diff -ur vis-0.6/text.h vis-0.8/text.h >--- vis-0.6/text.h 2020-06-07 13:25:20 >+++ vis-0.8/text.h 2022-11-01 16:50:10 >@@ -12,7 +12,7 @@ > /** A mark. */ > typedef uintptr_t Mark; > >-/** An invalid mark, lookup of which will yield `EPOS`. */ >+/** An invalid mark, lookup of which will yield ``EPOS``. */ > #define EMARK ((Mark)0) > /** An invalid position. */ > #define EPOS ((size_t)-1) >@@ -75,13 +75,13 @@ > */ > TEXT_LOAD_READ, > /** >- * Memory map the the file from disk. Use file system / virtual memory >+ * Memory map the file from disk. Use file system / virtual memory > * subsystem as a caching layer. > * @rst > * .. note:: Load time is (almost) independent of the file size. > * .. warning:: Inplace modifications of the underlying file > * will be reflected in the current text content. >- * In particular, truncatenation will raise ``SIGBUS`` >+ * In particular, truncation will raise ``SIGBUS`` > * and result in data loss. > * @endrst > */ >@@ -95,6 +95,7 @@ > * @endrst > */ > Text *text_load(const char *filename); >+Text *text_loadat(int dirfd, const char *filename); > /** > * Create a text instance populated with the given file content. > * >@@ -109,7 +110,8 @@ > * @endrst > */ > Text *text_load_method(const char *filename, enum TextLoadMethod); >-/** Release all ressources associated with this text instance. */ >+Text *text_loadat_method(int dirfd, const char *filename, enum TextLoadMethod); >+/** Release all resources associated with this text instance. */ > void text_free(Text*); > /** > * @} >@@ -117,7 +119,7 @@ > * @{ > */ > /** Return the size in bytes of the whole text. */ >-size_t text_size(Text*); >+size_t text_size(const Text*); > /** > * Get file information at time of load or last save, whichever happened more > * recently. >@@ -128,9 +130,9 @@ > * @endrst > * @return See ``stat(2)`` for details. > */ >-struct stat text_stat(Text*); >+struct stat text_stat(const Text*); > /** Query whether the text contains any unsaved modifications. */ >-bool text_modified(Text*); >+bool text_modified(const Text*); > /** > * @} > * @defgroup modify >@@ -153,7 +155,7 @@ > * @return Whether the deletion succeeded. > */ > bool text_delete(Text*, size_t pos, size_t len); >-bool text_delete_range(Text*, Filerange*); >+bool text_delete_range(Text*, const Filerange*); > bool text_printf(Text*, size_t pos, const char *format, ...) __attribute__((format(printf, 3, 4))); > bool text_appendf(Text*, const char *format, ...) __attribute__((format(printf, 2, 3))); > /** >@@ -162,9 +164,9 @@ > * @{ > */ > /** >- * Create a text snapshot, that is a vertice in the history graph. >+ * Create a text snapshot, that is a vertex in the history graph. > */ >-void text_snapshot(Text*); >+bool text_snapshot(Text*); > /** > * Revert to previous snapshot along the main branch. > * @rst >@@ -195,7 +197,7 @@ > * .. note:: TODO: This is currently not the same as the time of the last snapshot. > * @endrst > */ >-time_t text_state(Text*); >+time_t text_state(const Text*); > /** > * @} > * @defgroup lines >@@ -219,9 +221,9 @@ > * return an artificial NUL byte at EOF. > * @endrst > */ >-bool text_byte_get(Text*, size_t pos, char *byte); >+bool text_byte_get(const Text*, size_t pos, char *byte); > /** >- * Store at most `len` bytes starting from ``pos`` into ``buf``. >+ * Store at most ``len`` bytes starting from ``pos`` into ``buf``. > * @param pos The absolute starting position. > * @param len The length in bytes. > * @param buf The destination buffer. >@@ -230,25 +232,29 @@ > * .. warning:: ``buf`` will not be NUL terminated. > * @endrst > */ >-size_t text_bytes_get(Text*, size_t pos, size_t len, char *buf); >+size_t text_bytes_get(const Text*, size_t pos, size_t len, char *buf); > /** > * Fetch text range into newly allocate memory region. > * @param pos The absolute starting position. > * @param len The length in bytes. >- * @return A contigious NUL terminated buffer holding the requested range, or >+ * @return A contiguous NUL terminated buffer holding the requested range, or > * ``NULL`` in error case. > * @rst >- * .. warning:: The returned pointer must be `free(3)`-ed by the caller. >+ * .. warning:: The returned pointer must be freed by the caller. > * @endrst > */ >-char *text_bytes_alloc0(Text*, size_t pos, size_t len); >+char *text_bytes_alloc0(const Text*, size_t pos, size_t len); > /** > * @} > * @defgroup iterator > * @{ > */ >-Iterator text_iterator_get(Text*, size_t pos); >+Iterator text_iterator_get(const Text*, size_t pos); >+bool text_iterator_init(const Text*, Iterator*, size_t pos); >+const Text *text_iterator_text(const Iterator*); > bool text_iterator_valid(const Iterator*); >+bool text_iterator_has_next(const Iterator*); >+bool text_iterator_has_prev(const Iterator*); > bool text_iterator_next(Iterator*); > bool text_iterator_prev(Iterator*); > /** >@@ -256,7 +262,7 @@ > * @defgroup iterator_byte > * @{ > */ >-bool text_iterator_byte_get(Iterator*, char *b); >+bool text_iterator_byte_get(const Iterator*, char *b); > bool text_iterator_byte_prev(Iterator*, char *b); > bool text_iterator_byte_next(Iterator*, char *b); > bool text_iterator_byte_find_prev(Iterator*, char b); >@@ -283,19 +289,19 @@ > /** > * Set a mark. > * @rst >- * .. note:: Setting a mark to `text_size` will always return the current text >- * size upon lookup. >+ * .. note:: Setting a mark to ``text_size`` will always return the >+ * current text size upon lookup. > * @endrst > * @param pos The position at which to store the mark. >- * @return The mark or `EMARK` if an invalid position was given. >+ * @return The mark or ``EMARK`` if an invalid position was given. > */ > Mark text_mark_set(Text*, size_t pos); > /** > * Lookup a mark. > * @param mark The mark to look up. >- * @return The byte position or `EPOS` for an invalid mark. >+ * @return The byte position or ``EPOS`` for an invalid mark. > */ >-size_t text_mark_get(Text*, Mark); >+size_t text_mark_get(const Text*, Mark); > /** > * @} > * @defgroup save >@@ -308,12 +314,12 @@ > /** Automatically chose best option. */ > TEXT_SAVE_AUTO, > /** >- * Save file atomically using `rename(2)`. >+ * Save file atomically using ``rename(2)``. > * > * Creates a temporary file, restores all important meta data, > * before moving it atomically to its final (possibly already >- * existing) destination using `rename(2)`. For new files, >- * permissions are set to `0666 & ~umask`. >+ * existing) destination using ``rename(2)``. For new files, >+ * permissions are set to ``0666 & ~umask``. > * > * @rst > * .. warning:: This approach does not work if: >@@ -323,7 +329,7 @@ > * - File ownership can not be preserved. > * - File group can not be preserved. > * - Directory permissions do not allow creation of a new file. >- * - POSXI ACL can not be preserved (if enabled). >+ * - POSIX ACL can not be preserved (if enabled). > * - SELinux security context can not be preserved (if enabled). > * @endrst > */ >@@ -339,39 +345,41 @@ > > /** > * Save the whole text to the given file name. >- */ >-bool text_save(Text*, const char *filename); >-/** >- * Save the whole text to the given file name, using the specified method. > * > * @rst > * .. note:: Equivalent to ``text_save_method(filename, TEXT_SAVE_AUTO)``. > * @endrst > */ >+bool text_save(Text*, const char *filename); >+bool text_saveat(Text*, int dirfd, const char *filename); >+/** >+ * Save the whole text to the given file name, using the specified method. >+ */ > bool text_save_method(Text*, const char *filename, enum TextSaveMethod); >+bool text_saveat_method(Text*, int dirfd, const char *filename, enum TextSaveMethod); > > /** > * Setup a sequence of write operations. > * >- * The returned `TextSave` pointer can be used to write multiple, possibly >- * non-contigious, file ranges. >+ * The returned ``TextSave`` pointer can be used to write multiple, possibly >+ * non-contiguous, file ranges. > * @rst >- * .. warning:: For every call to `text_save_begin` there must be exactly >- * one matching call to either `text_save_commit` or >- * `text_save_cancel` to release the underlying resources. >+ * .. warning:: For every call to ``text_save_begin`` there must be exactly >+ * one matching call to either ``text_save_commit`` or >+ * ``text_save_cancel`` to release the underlying resources. > * @endrst > */ >-TextSave *text_save_begin(Text*, const char *filename, enum TextSaveMethod); >+TextSave *text_save_begin(Text*, int dirfd, const char *filename, enum TextSaveMethod); > /** > * Write file range. > * @return The number of bytes written or ``-1`` in case of an error. > */ >-ssize_t text_save_write_range(TextSave*, Filerange*); >+ssize_t text_save_write_range(TextSave*, const Filerange*); > /** > * Commit changes to disk. > * @return Whether changes have been saved. > * @rst >- * .. note:: Releases the underlying resources and `free(3)`'s the given `TextSave` >+ * .. note:: Releases the underlying resources and frees the given ``TextSave`` > * pointer which must no longer be used. > * @endrst > */ >@@ -381,7 +389,7 @@ > * @rst > * .. note:: Does not guarantee to undo the previous writes (they might have been > * performed in-place). However, it releases the underlying resources and >- * `free(3)`'s the given `TextSave` pointer which must no longer be used. >+ * frees the given ``TextSave`` pointer which must no longer be used. > * @endrst > */ > void text_save_cancel(TextSave*); >@@ -389,12 +397,12 @@ > * Write whole text content to file descriptor. > * @return The number of bytes written or ``-1`` in case of an error. > */ >-ssize_t text_write(Text*, int fd); >+ssize_t text_write(const Text*, int fd); > /** > * Write file range to file descriptor. > * @return The number of bytes written or ``-1`` in case of an error. > */ >-ssize_t text_write_range(Text*, Filerange*, int fd); >+ssize_t text_write_range(const Text*, const Filerange*, int fd); > /** > * @} > * @defgroup misc >@@ -404,7 +412,7 @@ > * Check whether ``ptr`` is part of a memory mapped region associated with > * this text instance. > */ >-bool text_mmaped(Text*, const char *ptr); >+bool text_mmaped(const Text*, const char *ptr); > /** @} */ > > #endif >diff -ur vis-0.6/ui.h vis-0.8/ui.h >--- vis-0.6/ui.h 2020-06-07 13:25:20 >+++ vis-0.8/ui.h 2022-11-01 16:50:10 >@@ -7,7 +7,7 @@ > > /* enable large file optimization for files larger than: */ > #define UI_LARGE_FILE_SIZE (1 << 25) >-/* enable large file optimization fo files containing lines longer than: */ >+/* enable large file optimization for files containing lines longer than: */ > #define UI_LARGE_FILE_LINE_SIZE (1 << 16) > > typedef struct Ui Ui; >diff -ur vis-0.6/view.c vis-0.8/view.c >--- vis-0.6/view.c 2020-06-07 13:25:20 >+++ vis-0.8/view.c 2022-11-01 16:50:10 >@@ -358,7 +358,7 @@ > cell = (Cell){ .data = "\xEF\xBF\xBD", .len = len, .width = 1 }; > } else if (len == (size_t)-2) { > /* not enough bytes available to convert to a >- * wide character. advance file position and read >+ * wide character. Advance file position and read > * another junk into buffer. > */ > rem = text_bytes_get(view->text, pos+prev_cell.len, size, text); >@@ -1196,8 +1196,11 @@ > } > > void view_selections_dispose_all(View *view) { >- for (Selection *s = view->selections, *next; s; s = next) { >- next = s->next; >+ Selection *last = view->selections; >+ while (last->next) >+ last = last->next; >+ for (Selection *s = last, *prev; s; s = prev) { >+ prev = s->prev; > if (s != view->selection) > selection_free(s); > } >diff -ur vis-0.6/view.h vis-0.8/view.h >--- vis-0.6/view.h 2020-06-07 13:25:20 >+++ vis-0.8/view.h 2022-11-01 16:50:10 >@@ -56,13 +56,13 @@ > /** > * Get window coordinate of text position. > * @param pos The position to query. >- * @param line Will be updated with screen line on which `pos` resides. >- * @param row Will be updaded with zero based window row on which `pos` resides. >- * @param col Will be updated with zero based window column which `pos` resides. >- * @return Whether `pos` is visible. If not, the pointer arguments are left unmodified. >+ * @param line Will be updated with screen line on which ``pos`` resides. >+ * @param row Will be updaded with zero based window row on which ``pos`` resides. >+ * @param col Will be updated with zero based window column on which ``pos`` resides. >+ * @return Whether ``pos`` is visible. If not, the pointer arguments are left unmodified. > */ > bool view_coord_get(View*, size_t pos, Line **line, int *row, int *col); >-/** Get position at the start ot the `n`-th window line, counting from 1. */ >+/** Get position at the start of the ``n``-th window line, counting from 1. */ > size_t view_screenline_goto(View*, int n); > /** Get first screen line. */ > Line *view_lines_first(View*); >@@ -122,7 +122,7 @@ > /** > * Dispose an existing selection. > * @rst >- * .. warning:: Not applicaple for the last existing selection. >+ * .. warning:: Not applicable for the last existing selection. > * @endrst > */ > bool view_selections_dispose(Selection*); >@@ -138,7 +138,7 @@ > * Query state of primary selection. > * > * If the primary selection was marked for destruction, return it and >- * clear descruction flag. >+ * clear destruction flag. > */ > Selection *view_selection_disposed(View*); > /** Dispose all but the primary selection. */ >@@ -147,7 +147,7 @@ > void view_selections_normalize(View*); > /** > * Replace currently active selections. >- * @param array The Array of ``Filerange``s. >+ * @param array The array of ``Filerange`` objects. > * @param anchored Whether *all* selection should be anchored. > */ > void view_selections_set_all(View*, Array*, bool anchored); >@@ -176,7 +176,7 @@ > /** > * Get selection index. > * @rst >- * .. note:: Is always in range `[0, count-1]`. >+ * .. note:: Is always in range ``[0, count-1]``. > * .. warning: The relative order is determined during creation and assumed > * to remain the same. > * @endrst >@@ -259,7 +259,7 @@ > /** > * Get zero based index of screen cell on which selection cursor currently resides. > * @rst >- * .. warning:: Returns `-1` if the selection cursor is currently not visible. >+ * .. warning:: Returns ``-1`` if the selection cursor is currently not visible. > * @endrst > */ > int view_cursors_cell_get(Selection*); >@@ -324,7 +324,7 @@ > */ > /** > * Move primary selection cursor to the given position. >- * Makes sure that position is visisble. >+ * Makes sure that position is visible. > * @rst > * .. note:: If position was not visible before, we attempt to show > * surrounding context. The viewport will be adjusted such >diff -ur vis-0.6/vis-clipboard vis-0.8/vis-clipboard >--- vis-0.6/vis-clipboard 2020-06-07 13:25:20 >+++ vis-0.8/vis-clipboard 2022-11-01 16:50:10 >@@ -8,10 +8,19 @@ > } > > vc_usage() { >- vc_fatal "`basename $0` [--usable|--copy|--paste]" >+ vc_fatal "`basename $0` [--selection sel] [--usable|--copy|--paste]" > } > > vc_determine_command() { >+ if [ -n "$WAYLAND_DISPLAY" ]; then >+ for c in wl-copy wl-paste; do >+ if type "$c" >/dev/null 2>&1; then >+ echo "wlclipboard" >+ return 0 >+ fi >+ done >+ fi >+ > if [ -n "$DISPLAY" ]; then > for c in xclip xsel; do > if type "$c" >/dev/null 2>&1; then >@@ -21,6 +30,10 @@ > done > fi > >+ if [ "$sel" = "primary" ]; then >+ vc_fatal "clipboard primary selection is not supported on your platform" >+ fi >+ > if type pbcopy >/dev/null 2>&1; then > echo 'mac' > return 0 >@@ -66,20 +79,36 @@ > exit $? > } > >+vc_wlclipboard_copy() { >+ if [ "$sel" = "primary" ]; then >+ wl-copy --primary -t TEXT >+ else >+ wl-copy -t TEXT >+ fi >+} >+ >+vc_wlclipboard_paste() { >+ if [ "$sel" = "primary" ]; then >+ wl-paste --primary -t text >+ else >+ wl-paste -t text >+ fi >+} >+ > vc_xsel_copy() { >- xsel -bi >+ xsel --"$sel" -bi > } > > vc_xsel_paste() { >- xsel -bo >+ xsel --"$sel" -bo > } > > vc_xclip_copy() { >- xclip -selection clipboard -i >/dev/null 2>&1 >+ xclip -selection "$sel" -i >/dev/null 2>&1 > } > > vc_xclip_paste() { >- xclip -selection clipboard -o >+ xclip -selection "$sel" -o > } > > vc_mac_copy() { >@@ -98,11 +127,17 @@ > cat /dev/clipboard > } > >-case "$1" in >- --usable) vc_usable;; >- --copy) vc_copy;; >- --paste) vc_paste;; >- *) ;; >-esac >+while [ $# -gt 0 ]; do >+ case "$1" in >+ --usable) fn=vc_usable;; >+ --copy) fn=vc_copy;; >+ --paste) fn=vc_paste;; >+ --selection) shift; sel="$1";; >+ *) ;; >+ esac >+ shift >+done >+ >+sel=${sel:-"clipboard"} $fn > > vc_usage >diff -ur vis-0.6/vis-cmds.c vis-0.8/vis-cmds.c >--- vis-0.6/vis-cmds.c 2020-06-07 13:25:20 >+++ vis-0.8/vis-cmds.c 2022-11-01 16:50:10 >@@ -361,6 +361,9 @@ > windows_arrange(vis, layout); > break; > } >+ case OPTION_IGNORECASE: >+ vis->ignorecase = toggle ? !vis->ignorecase : arg.b; >+ break; > default: > if (!opt->func) > return false; >@@ -616,9 +619,10 @@ > } > } > >+ struct tm tm; > time_t state = text_state(txt); > char buf[32]; >- strftime(buf, sizeof buf, "State from %H:%M", localtime(&state)); >+ strftime(buf, sizeof buf, "State from %H:%M", localtime_r(&state, &tm)); > vis_info_show(vis, "%s", buf); > > return pos != EPOS; >diff -ur vis-0.6/vis-core.h vis-0.8/vis-core.h >--- vis-0.6/vis-core.h 2020-06-07 13:25:20 >+++ vis-0.8/vis-core.h 2022-11-01 16:50:10 >@@ -14,7 +14,7 @@ > > /* a mode contains a set of key bindings which are currently valid. > * >- * each mode can specify one parent mode which is consultated if a given key >+ * each mode can specify one parent mode which is consulted if a given key > * is not found in the current mode. hence the modes form a tree which is > * searched from the current mode up towards the root mode until a valid binding > * is found. >@@ -63,13 +63,13 @@ > }; > > typedef struct { >- /* operator logic, returns new cursor position, if EPOS is >+ /* operator logic, returns new cursor position, if EPOS > * the cursor is disposed (except if it is the primary one) */ > VisOperatorFunction *func; > void *context; > } Operator; > >-typedef struct { /* Motion implementation, takes a cursor postion and returns a new one */ >+typedef struct { /* Motion implementation, takes a cursor position and returns a new one */ > /* TODO: merge types / use union to save space */ > size_t (*cur)(Selection*); > size_t (*txt)(Text*, size_t pos); >@@ -154,7 +154,7 @@ > }; > > struct Win { >- Vis *vis; /* editor instance to which this window belongs to */ >+ Vis *vis; /* editor instance to which this window belongs */ > UiWin *ui; /* ui object handling visual appearance of this window */ > File *file; /* file being displayed in this window */ > View *view; /* currently displayed part of underlying text */ >@@ -167,7 +167,7 @@ > }; > > struct Vis { >- Ui *ui; /* user interface repsonsible for visual appearance */ >+ Ui *ui; /* user interface responsible for visual appearance */ > File *files; /* all files currently managed by this editor instance */ > File *command_file; /* special internal file used to store :-command prompt */ > File *search_file; /* special internal file used to store /,? search prompt */ >@@ -201,26 +201,27 @@ > Action action; /* current action which is in progress */ > Action action_prev; /* last operator action used by the repeat (dot) command */ > Mode *mode; /* currently active mode, used to search for keybindings */ >- Mode *mode_prev; /* previsouly active user mode */ >+ Mode *mode_prev; /* previously active user mode */ > bool initialized; /* whether UI and Lua integration has been initialized */ > int nesting_level; /* parsing state to hold keep track of { } nesting level */ > volatile bool running; /* exit main loop once this becomes false */ > int exit_status; /* exit status when terminating main loop */ > volatile sig_atomic_t interrupted; /* abort command (SIGINT occured) */ >- volatile sig_atomic_t sigbus; /* one of the memory mapped region became unavailable (SIGBUS) */ >+ volatile sig_atomic_t sigbus; /* one of the memory mapped regions became unavailable (SIGBUS) */ > volatile sig_atomic_t need_resize; /* need to resize UI (SIGWINCH occured) */ > volatile sig_atomic_t resume; /* need to resume UI (SIGCONT occured) */ > volatile sig_atomic_t terminate; /* need to terminate we were being killed by SIGTERM */ > sigjmp_buf sigbus_jmpbuf; /* used to jump back to a known good state in the mainloop after (SIGBUS) */ > Map *actions; /* registered editor actions / special keys commands */ > Array actions_user; /* dynamically allocated editor actions */ >- lua_State *lua; /* lua context used for syntax highligthing */ >+ lua_State *lua; /* lua context used for syntax highlighting */ > enum TextLoadMethod load_method; /* how existing files should be loaded */ > VisEvent *event; > Array operators; > Array motions; > Array textobjects; > Array bindings; >+ bool ignorecase; /* whether to ignore case when searching */ > }; > > enum VisEvents { >@@ -235,6 +236,7 @@ > VIS_EVENT_WIN_CLOSE, > VIS_EVENT_WIN_HIGHLIGHT, > VIS_EVENT_WIN_STATUS, >+ VIS_EVENT_TERM_CSI, > }; > > bool vis_event_emit(Vis*, enum VisEvents, ...); >@@ -246,7 +248,7 @@ > > typedef MarkDef RegisterDef; > >-/** stuff used by multiple of the vis-* files */ >+/** stuff used by several of the vis-* files */ > > extern Mode vis_modes[VIS_MODE_INVALID]; > extern const Movement vis_motions[VIS_MOVE_INVALID]; >diff -ur vis-0.6/vis-lua.c vis-0.8/vis-lua.c >--- vis-0.6/vis-lua.c 2020-06-07 13:25:20 >+++ vis-0.8/vis-lua.c 2022-11-01 16:50:10 >@@ -161,6 +161,7 @@ > void vis_lua_win_close(Vis *vis, Win *win) { } > void vis_lua_win_highlight(Vis *vis, Win *win) { } > void vis_lua_win_status(Vis *vis, Win *win) { window_status_update(vis, win); } >+void vis_lua_term_csi(Vis *vis, const long *csi) { } > > #else > >@@ -330,7 +331,7 @@ > lua_getfield(L, LUA_REGISTRYINDEX, "vis.types"); > lua_getmetatable(L, -2); > lua_gettable(L, -2); >- // XXX: in theory string might become invalid when poped from stack >+ // XXX: in theory string might become invalid when popped from stack > const char *type = lua_tostring(L, -1); > lua_pop(L, 2); > return type; >@@ -675,30 +676,28 @@ > * @usage > * local marks = vis.win.marks > * for name in vis:mark_names() do >- * local mark = marks[name] >- * for i = 1, #mark do >+ * local mark = marks[name] >+ * for i = 1, #mark do > * -- do somthing with: name, mark[i].start, mark[i].finish >- * end >+ * end > * end > */ > static int mark_names_iter(lua_State *L); > static int mark_names(lua_State *L) { >+ Vis *vis = obj_ref_check(L, 1, "vis"); >+ lua_pushlightuserdata(L, vis); > enum VisMark *handle = lua_newuserdata(L, sizeof *handle); > *handle = 0; >- lua_pushcclosure(L, mark_names_iter, 1); >+ lua_pushcclosure(L, mark_names_iter, 2); > return 1; > } > > static int mark_names_iter(lua_State *L) { >- char mark = '\0'; >- enum VisMark *handle = lua_touserdata(L, lua_upvalueindex(1)); >- if (*handle < LENGTH(vis_marks)) >- mark = vis_marks[*handle].name; >- else if (VIS_MARK_a <= *handle && *handle <= VIS_MARK_z) >- mark = 'a' + *handle - VIS_MARK_a; >+ Vis *vis = lua_touserdata(L, lua_upvalueindex(1)); >+ enum VisMark *handle = lua_touserdata(L, lua_upvalueindex(2)); >+ char mark = vis_mark_to(vis, *handle); > if (mark) { >- char name[2] = { mark, '\0' }; >- lua_pushstring(L, name); >+ lua_pushlstring(L, &mark, 1); > (*handle)++; > return 1; > } >@@ -719,22 +718,20 @@ > */ > static int register_names_iter(lua_State *L); > static int register_names(lua_State *L) { >+ Vis *vis = obj_ref_check(L, 1, "vis"); >+ lua_pushlightuserdata(L, vis); > enum VisRegister *handle = lua_newuserdata(L, sizeof *handle); > *handle = 0; >- lua_pushcclosure(L, register_names_iter, 1); >+ lua_pushcclosure(L, register_names_iter, 2); > return 1; > } > > static int register_names_iter(lua_State *L) { >- char reg = '\0'; >- enum VisRegister *handle = lua_touserdata(L, lua_upvalueindex(1)); >- if (*handle < LENGTH(vis_registers)) >- reg = vis_registers[*handle].name; >- else if (VIS_REG_a <= *handle && *handle <= VIS_REG_z) >- reg = 'a' + *handle - VIS_REG_a; >+ Vis *vis = lua_touserdata(L, lua_upvalueindex(1)); >+ enum VisRegister *handle = lua_touserdata(L, lua_upvalueindex(2)); >+ char reg = vis_register_to(vis, *handle); > if (reg) { >- char name[2] = { reg, '\0' }; >- lua_pushstring(L, name); >+ lua_pushlstring(L, ®, 1); > (*handle)++; > return 1; > } >@@ -761,7 +758,7 @@ > * Display a short message. > * > * The single line message will be displayed at the bottom of >- * the scren and automatically hidden once a key is pressed. >+ * the screen and automatically hidden once a key is pressed. > * > * @function info > * @tparam string message the message to display >@@ -1312,7 +1309,7 @@ > * eventually hands over control to the editor core. The exit status > * of the most recent call is used. > * >- * All unsaved chanes will be lost! >+ * All unsaved changes will be lost! > * > * @function exit > * @tparam int code the exit status returned to the operating system >@@ -1363,7 +1360,7 @@ > * > * Will trigger redraw events, make sure to avoid recursive events. > * >- * @function draw >+ * @function redraw > */ > static int redraw(lua_State *L) { > Vis *vis = obj_ref_check(L, 1, "vis"); >@@ -1387,6 +1384,14 @@ > * Currently unconsumed keys in the input queue. > * @tfield string input_queue > */ >+/*** >+ * Register name in use. >+ * @tfield string register >+ */ >+/*** >+ * Mark name in use. >+ * @tfield string mark >+ */ > static int vis_index(lua_State *L) { > Vis *vis = obj_ref_check(L, 1, "vis"); > >@@ -1424,11 +1429,23 @@ > return 1; > } > >+ if (strcmp(key, "register") == 0) { >+ char name = vis_register_to(vis, vis_register_used(vis)); >+ lua_pushlstring(L, &name, 1); >+ return 1; >+ } >+ > if (strcmp(key, "registers") == 0) { > obj_ref_new(L, vis->ui, VIS_LUA_TYPE_REGISTERS); > return 1; > } > >+ if (strcmp(key, "mark") == 0) { >+ char name = vis_mark_to(vis, vis_mark_used(vis)); >+ lua_pushlstring(L, &name, 1); >+ return 1; >+ } >+ > if (strcmp(key, "ui") == 0) { > obj_ref_new(L, vis->ui, VIS_LUA_TYPE_UI); > return 1; >@@ -1462,6 +1479,20 @@ > vis_window_focus(obj_ref_check(L, 3, VIS_LUA_TYPE_WINDOW)); > return 0; > } >+ >+ if (strcmp(key, "register") == 0) { >+ const char *name = luaL_checkstring(L, 3); >+ if (strlen(name) == 1) >+ vis_register(vis, vis_register_from(vis, name[0])); >+ return 0; >+ } >+ >+ if (strcmp(key, "mark") == 0) { >+ const char *name = luaL_checkstring(L, 3); >+ if (strlen(name) == 1) >+ vis_mark(vis, vis_mark_from(vis, name[0])); >+ return 0; >+ } > } > return newindex_common(L); > } >@@ -2066,6 +2097,10 @@ > * File state. > * @tfield bool modified whether the file contains unsaved changes > */ >+/*** >+ * File permission. >+ * @tfield int permission the file permission bits as of the most recent load/save >+ */ > static int file_index(lua_State *L) { > File *file = obj_ref_check(L, 1, VIS_LUA_TYPE_FILE); > >@@ -2095,11 +2130,38 @@ > lua_pushboolean(L, text_modified(file->text)); > return 1; > } >+ >+ if (strcmp(key, "permission") == 0) { >+ struct stat stat = text_stat(file->text); >+ lua_pushunsigned(L, stat.st_mode & 0777); >+ return 1; >+ } > } > > return index_common(L); > } > >+static int file_newindex(lua_State *L) { >+ File *file = obj_ref_check(L, 1, VIS_LUA_TYPE_FILE); >+ >+ if (lua_isstring(L, 2)) { >+ const char *key = lua_tostring(L, 2); >+ >+ if (strcmp(key, "modified") == 0) { >+ bool modified = lua_isboolean(L, 3) && lua_toboolean(L, 3); >+ if (modified) { >+ text_insert(file->text, 0, " ", 1); >+ text_delete(file->text, 0, 1); >+ } else { >+ text_save(file->text, NULL); >+ } >+ return 0; >+ } >+ } >+ >+ return newindex_common(L); >+} >+ > /*** > * Insert data at position. > * @function insert >@@ -2281,7 +2343,7 @@ > > static const struct luaL_Reg file_funcs[] = { > { "__index", file_index }, >- { "__newindex", newindex_common }, >+ { "__newindex", file_newindex }, > { "insert", file_insert }, > { "delete", file_delete }, > { "lines_iterator", file_lines_iterator }, >@@ -2860,7 +2922,7 @@ > * Input key event in either input or replace mode. > * @function input > * @tparam string key >- * @treturn bool whether the key was cosumed or not >+ * @treturn bool whether the key was consumed or not > */ > static bool vis_lua_input(Vis *vis, const char *key, size_t len) { > lua_State *L = vis->lua; >@@ -3050,6 +3112,26 @@ > pcall(vis, L, 1, 0); > } else { > window_status_update(vis, win); >+ } >+ lua_pop(L, 1); >+} >+ >+/*** >+ * CSI command received from terminal. >+ * @function term_csi >+ * @param List of CSI parameters >+ */ >+void vis_lua_term_csi(Vis *vis, const long *csi) { >+ lua_State *L = vis->lua; >+ if (!L) >+ return; >+ vis_lua_event_get(L, "term_csi"); >+ if (lua_isfunction(L, -1)) { >+ int nargs = csi[1]; >+ lua_pushinteger(L, csi[0]); >+ for (int i = 0; i < nargs; i++) >+ lua_pushinteger(L, csi[2 + i]); >+ pcall(vis, L, 1 + nargs, 0); > } > lua_pop(L, 1); > } >diff -ur vis-0.6/vis-lua.h vis-0.8/vis-lua.h >--- vis-0.6/vis-lua.h 2020-06-07 13:25:20 >+++ vis-0.8/vis-lua.h 2022-11-01 16:50:10 >@@ -37,5 +37,6 @@ > void vis_lua_win_close(Vis*, Win*); > void vis_lua_win_highlight(Vis*, Win*); > void vis_lua_win_status(Vis*, Win*); >+void vis_lua_term_csi(Vis*, const long *); > > #endif >diff -ur vis-0.6/vis-marks.c vis-0.8/vis-marks.c >--- vis-0.6/vis-marks.c 2020-06-07 13:25:20 >+++ vis-0.8/vis-marks.c 2022-11-01 16:50:10 >@@ -226,6 +226,16 @@ > return VIS_MARK_INVALID; > } > >+char vis_mark_to(Vis *vis, enum VisMark mark) { >+ if (VIS_MARK_a <= mark && mark <= VIS_MARK_z) >+ return 'a' + mark - VIS_MARK_a; >+ >+ if (mark < LENGTH(vis_marks)) >+ return vis_marks[mark].name; >+ >+ return '\0'; >+} >+ > const MarkDef vis_marks[] = { > [VIS_MARK_DEFAULT] = { '\'', VIS_HELP("Default mark") }, > [VIS_MARK_SELECTION] = { '^', VIS_HELP("Last selections") }, >diff -ur vis-0.6/vis-motions.c vis-0.8/vis-motions.c >--- vis-0.6/vis-motions.c 2020-06-07 13:25:20 >+++ vis-0.8/vis-motions.c 2022-11-01 16:50:10 >@@ -112,8 +112,34 @@ > VIS_MOVE_LONGWORD_END_NEXT, isspace); > } > >-static size_t to(Vis *vis, Text *txt, size_t pos) { >+static size_t to_right(Vis *vis, Text *txt, size_t pos) { > char c; >+ size_t hit = text_find_next(txt, pos+1, vis->search_char); >+ if (!text_byte_get(txt, hit, &c) || c != vis->search_char[0]) >+ return pos; >+ return hit; >+} >+ >+static size_t till_right(Vis *vis, Text *txt, size_t pos) { >+ size_t hit = to_right(vis, txt, pos+1); >+ if (hit != pos) >+ return text_char_prev(txt, hit); >+ return pos; >+} >+ >+static size_t to_left(Vis *vis, Text *txt, size_t pos) { >+ return text_find_prev(txt, pos, vis->search_char); >+} >+ >+static size_t till_left(Vis *vis, Text *txt, size_t pos) { >+ size_t hit = to_left(vis, txt, pos-1); >+ if (hit != pos-1) >+ return text_char_next(txt, hit); >+ return pos; >+} >+ >+static size_t to_line_right(Vis *vis, Text *txt, size_t pos) { >+ char c; > if (pos == text_line_end(txt, pos)) > return pos; > size_t hit = text_line_find_next(txt, pos+1, vis->search_char); >@@ -122,8 +148,8 @@ > return hit; > } > >-static size_t till(Vis *vis, Text *txt, size_t pos) { >- size_t hit = to(vis, txt, pos+1); >+static size_t till_line_right(Vis *vis, Text *txt, size_t pos) { >+ size_t hit = to_line_right(vis, txt, pos+1); > if (pos == text_line_end(txt, pos)) > return pos; > if (hit != pos) >@@ -131,14 +157,14 @@ > return pos; > } > >-static size_t to_left(Vis *vis, Text *txt, size_t pos) { >+static size_t to_line_left(Vis *vis, Text *txt, size_t pos) { > return text_line_find_prev(txt, pos, vis->search_char); > } > >-static size_t till_left(Vis *vis, Text *txt, size_t pos) { >+static size_t till_line_left(Vis *vis, Text *txt, size_t pos) { > if (pos == text_line_begin(txt, pos)) > return pos; >- size_t hit = to_left(vis, txt, pos-1); >+ size_t hit = to_line_left(vis, txt, pos-1); > if (hit != pos-1) > return text_char_next(txt, hit); > return pos; >@@ -294,10 +320,14 @@ > } > break; > } >- case VIS_MOVE_RIGHT_TO: >- case VIS_MOVE_LEFT_TO: >- case VIS_MOVE_RIGHT_TILL: >- case VIS_MOVE_LEFT_TILL: >+ case VIS_MOVE_TO_RIGHT: >+ case VIS_MOVE_TO_LEFT: >+ case VIS_MOVE_TO_LINE_RIGHT: >+ case VIS_MOVE_TO_LINE_LEFT: >+ case VIS_MOVE_TILL_RIGHT: >+ case VIS_MOVE_TILL_LEFT: >+ case VIS_MOVE_TILL_LINE_RIGHT: >+ case VIS_MOVE_TILL_LINE_LEFT: > { > const char *key = va_arg(ap, char*); > if (!key) >@@ -314,18 +344,30 @@ > break; > case VIS_MOVE_TOTILL_REVERSE: > switch (vis->last_totill) { >- case VIS_MOVE_RIGHT_TO: >- motion = VIS_MOVE_LEFT_TO; >+ case VIS_MOVE_TO_RIGHT: >+ motion = VIS_MOVE_TO_LEFT; > break; >- case VIS_MOVE_LEFT_TO: >- motion = VIS_MOVE_RIGHT_TO; >+ case VIS_MOVE_TO_LEFT: >+ motion = VIS_MOVE_TO_RIGHT; > break; >- case VIS_MOVE_RIGHT_TILL: >- motion = VIS_MOVE_LEFT_TILL; >+ case VIS_MOVE_TO_LINE_RIGHT: >+ motion = VIS_MOVE_TO_LINE_LEFT; > break; >- case VIS_MOVE_LEFT_TILL: >- motion = VIS_MOVE_RIGHT_TILL; >+ case VIS_MOVE_TO_LINE_LEFT: >+ motion = VIS_MOVE_TO_LINE_RIGHT; > break; >+ case VIS_MOVE_TILL_RIGHT: >+ motion = VIS_MOVE_TILL_LEFT; >+ break; >+ case VIS_MOVE_TILL_LEFT: >+ motion = VIS_MOVE_TILL_RIGHT; >+ break; >+ case VIS_MOVE_TILL_LINE_RIGHT: >+ motion = VIS_MOVE_TILL_LINE_LEFT; >+ break; >+ case VIS_MOVE_TILL_LINE_LEFT: >+ motion = VIS_MOVE_TILL_LINE_RIGHT; >+ break; > default: > goto err; > } >@@ -515,20 +557,36 @@ > .txt = lastline, > .type = LINEWISE|LINEWISE_INCLUSIVE|JUMP|IDEMPOTENT, > }, >- [VIS_MOVE_LEFT_TO] = { >+ [VIS_MOVE_TO_LEFT] = { > .vis = to_left, > .type = COUNT_EXACT, > }, >- [VIS_MOVE_RIGHT_TO] = { >- .vis = to, >+ [VIS_MOVE_TO_RIGHT] = { >+ .vis = to_right, > .type = INCLUSIVE|COUNT_EXACT, > }, >- [VIS_MOVE_LEFT_TILL] = { >+ [VIS_MOVE_TO_LINE_LEFT] = { >+ .vis = to_line_left, >+ .type = COUNT_EXACT, >+ }, >+ [VIS_MOVE_TO_LINE_RIGHT] = { >+ .vis = to_line_right, >+ .type = INCLUSIVE|COUNT_EXACT, >+ }, >+ [VIS_MOVE_TILL_LEFT] = { > .vis = till_left, > .type = COUNT_EXACT, > }, >- [VIS_MOVE_RIGHT_TILL] = { >- .vis = till, >+ [VIS_MOVE_TILL_RIGHT] = { >+ .vis = till_right, >+ .type = INCLUSIVE|COUNT_EXACT, >+ }, >+ [VIS_MOVE_TILL_LINE_LEFT] = { >+ .vis = till_line_left, >+ .type = COUNT_EXACT, >+ }, >+ [VIS_MOVE_TILL_LINE_RIGHT] = { >+ .vis = till_line_right, > .type = INCLUSIVE|COUNT_EXACT, > }, > [VIS_MOVE_SEARCH_WORD_FORWARD] = { >diff -ur vis-0.6/vis-open vis-0.8/vis-open >--- vis-0.6/vis-open 2020-06-07 13:25:20 >+++ vis-0.8/vis-open 2022-11-01 16:50:10 >@@ -8,6 +8,15 @@ > VIS_MENU_PROMPT="" > ALLOW_AUTO_SELECT=1 > >+wrap_dirs() { >+ local o >+ >+ while read o >+ do >+ [ -d "$o" ] && printf "%s/\n" "$o" || printf "%s\n" "$o" >+ done >+} >+ > while [ $# -gt 0 ]; do > case "$1" in > -h|--help) >@@ -63,7 +72,7 @@ > > # At this point, we have a bunch of options we need to present to the > # user so they can pick one. >-CHOICE=$(printf "%s\n" "$@" | vis-menu -b -p "$VIS_MENU_PROMPT") >+CHOICE=$(printf "%s\n" "$@" | wrap_dirs | vis-menu -b -p "$VIS_MENU_PROMPT") > > # Did they pick a file or directory? Who knows, let's let the next iteration figure it out. > exec "$0" -p "$VIS_MENU_PROMPT" -- "$CHOICE" >diff -ur vis-0.6/vis-prompt.c vis-0.8/vis-prompt.c >--- vis-0.6/vis-prompt.c 2020-06-07 13:25:20 >+++ vis-0.8/vis-prompt.c 2022-11-01 16:50:10 >@@ -63,7 +63,8 @@ > pattern = "^:"; > else if (prompt->file == vis->search_file) > pattern = "^(/|\\?)"; >- if (pattern && regex && text_regex_compile(regex, pattern, REG_EXTENDED|REG_NEWLINE) == 0) { >+ int cflags = REG_EXTENDED|REG_NEWLINE|(REG_ICASE*vis->ignorecase); >+ if (pattern && regex && text_regex_compile(regex, pattern, cflags) == 0) { > size_t end = text_line_end(txt, pos); > size_t prev = text_search_backward(txt, end, regex); > if (prev > pos) >diff -ur vis-0.6/vis-registers.c vis-0.8/vis-registers.c >--- vis-0.6/vis-registers.c 2020-06-07 13:25:20 >+++ vis-0.8/vis-registers.c 2022-11-01 16:50:10 >@@ -69,16 +69,21 @@ > case REGISTER_CLIPBOARD: > { > Buffer buferr; >+ enum VisRegister id = reg - vis->registers; >+ const char *cmd[] = { VIS_CLIPBOARD, "--paste", "--selection", NULL, NULL }; > buffer_init(&buferr); > Buffer *buf = array_get(®->values, slot); > if (!buf) > return NULL; > buffer_clear(buf); > >+ if (id == VIS_REG_PRIMARY) >+ cmd[3] = "primary"; >+ else >+ cmd[3] = "clipboard"; > int status = vis_pipe(vis, vis->win->file, > &(Filerange){ .start = 0, .end = 0 }, >- (const char*[]){ VIS_CLIPBOARD, "--paste", NULL }, >- buf, read_buffer, &buferr, read_buffer); >+ cmd, buf, read_buffer, &buferr, read_buffer); > > if (status != 0) > vis_info_show(vis, "Command failed %s", buffer_content0(&buferr)); >@@ -152,11 +157,17 @@ > case REGISTER_CLIPBOARD: > { > Buffer buferr; >+ const char *cmd[] = { VIS_CLIPBOARD, "--copy", "--selection", NULL, NULL }; >+ enum VisRegister id = reg - vis->registers; > buffer_init(&buferr); > >+ if (id == VIS_REG_PRIMARY) >+ cmd[3] = "primary"; >+ else >+ cmd[3] = "clipboard"; >+ > int status = vis_pipe(vis, vis->win->file, range, >- (const char*[]){ VIS_CLIPBOARD, "--copy", NULL }, >- NULL, NULL, &buferr, read_buffer); >+ cmd, NULL, NULL, &buferr, read_buffer); > > if (status != 0) > vis_info_show(vis, "Command failed %s", buffer_content0(&buferr)); >@@ -186,15 +197,15 @@ > } > > enum VisRegister vis_register_from(Vis *vis, char reg) { >- switch (reg) { >- case '+': return VIS_REG_CLIPBOARD; >- case '@': return VIS_MACRO_LAST_RECORDED; >- } > >+ if (reg == '@') >+ return VIS_MACRO_LAST_RECORDED; >+ > if ('a' <= reg && reg <= 'z') > return VIS_REG_a + reg - 'a'; > if ('A' <= reg && reg <= 'Z') > return VIS_REG_A + reg - 'A'; >+ > for (size_t i = 0; i < LENGTH(vis_registers); i++) { > if (vis_registers[i].name == reg) > return i; >@@ -202,6 +213,22 @@ > return VIS_REG_INVALID; > } > >+char vis_register_to(Vis *vis, enum VisRegister reg) { >+ >+ if (reg == VIS_MACRO_LAST_RECORDED) >+ return '@'; >+ >+ if (VIS_REG_a <= reg && reg <= VIS_REG_z) >+ return 'a' + reg - VIS_REG_a; >+ if (VIS_REG_A <= reg && reg <= VIS_REG_Z) >+ return 'A' + reg - VIS_REG_A; >+ >+ if (reg < LENGTH(vis_registers)) >+ return vis_registers[reg].name; >+ >+ return '\0'; >+} >+ > void vis_register(Vis *vis, enum VisRegister reg) { > if (VIS_REG_A <= reg && reg <= VIS_REG_Z) { > vis->action.reg = &vis->registers[VIS_REG_a + reg - VIS_REG_A]; >@@ -275,7 +302,8 @@ > [VIS_REG_9] = { '9', VIS_HELP("9th sub-expression match") }, > [VIS_REG_AMPERSAND] = { '&', VIS_HELP("Last regex match") }, > [VIS_REG_BLACKHOLE] = { '_', VIS_HELP("/dev/null register") }, >- [VIS_REG_CLIPBOARD] = { '*', VIS_HELP("System clipboard register, see vis-clipboard(1)") }, >+ [VIS_REG_PRIMARY] = { '*', VIS_HELP("Primary clipboard register, see vis-clipboard(1)") }, >+ [VIS_REG_CLIPBOARD] = { '+', VIS_HELP("System clipboard register, see vis-clipboard(1)") }, > [VIS_REG_DOT] = { '.', VIS_HELP("Last inserted text") }, > [VIS_REG_SEARCH] = { '/', VIS_HELP("Last search pattern") }, > [VIS_REG_COMMAND] = { ':', VIS_HELP("Last :-command") }, >diff -ur vis-0.6/vis-text-objects.c vis-0.8/vis-text-objects.c >--- vis-0.6/vis-text-objects.c 2020-06-07 13:25:20 >+++ vis-0.8/vis-text-objects.c 2022-11-01 16:50:10 >@@ -173,12 +173,6 @@ > .txt = object_backtick, > .type = TEXTOBJECT_DELIMITED_INNER, > }, >- [VIS_TEXTOBJECT_OUTER_ENTIRE] = { >- .txt = text_object_entire, >- }, >- [VIS_TEXTOBJECT_INNER_ENTIRE] = { >- .txt = text_object_entire_inner, >- }, > [VIS_TEXTOBJECT_OUTER_LINE] = { > .txt = text_object_line, > }, >diff -ur vis-0.6/vis.c vis-0.8/vis.c >--- vis-0.6/vis.c 2020-06-07 13:25:20 >+++ vis-0.8/vis.c 2022-11-01 16:50:10 >@@ -100,6 +100,10 @@ > if (vis->event->quit) > vis->event->quit(vis); > break; >+ case VIS_EVENT_TERM_CSI: >+ if (vis->event->term_csi) >+ vis->event->term_csi(vis, va_arg(ap, const long *)); >+ break; > } > > va_end(ap); >@@ -675,6 +679,7 @@ > register_init(&vis->registers[i]); > vis->registers[VIS_REG_BLACKHOLE].type = REGISTER_BLACKHOLE; > vis->registers[VIS_REG_CLIPBOARD].type = REGISTER_CLIPBOARD; >+ vis->registers[VIS_REG_PRIMARY].type = REGISTER_CLIPBOARD; > vis->registers[VIS_REG_NUMBER].type = REGISTER_NUMBER; > array_init(&vis->operators); > array_init(&vis->motions); >@@ -1013,7 +1018,7 @@ > register_resize(reg, last_reg_slot+1); > } > >- /* we do not support visual repeat, still do something resonable */ >+ /* we do not support visual repeat, still do something reasonable */ > if (vis->mode->visual && !a->movement && !a->textobj) > a->movement = &vis_motions[VIS_MOVE_NOP]; > >@@ -1303,6 +1308,17 @@ > } > > TermKey *termkey = vis->ui->termkey_get(vis->ui); >+ if (key.type == TERMKEY_TYPE_UNKNOWN_CSI) { >+ long args[18]; >+ size_t nargs; >+ unsigned long cmd; >+ if (termkey_interpret_csi(termkey, &key, &args[2], &nargs, &cmd) == TERMKEY_RES_KEY) { >+ args[0] = (long)cmd; >+ args[1] = nargs; >+ vis_event_emit(vis, VIS_EVENT_TERM_CSI, args); >+ } >+ return getkey(vis); >+ } > termkey_strfkey(termkey, vis->key, sizeof(vis->key), &key, TERMKEY_FORMAT_VIM); > return vis->key; > } >@@ -1380,7 +1396,8 @@ > vis_die(vis, "Killed by SIGTERM\n"); > if (vis->interrupted) { > vis->interrupted = false; >- vis_keys_feed(vis, "<C-c>"); >+ vis_keys_push(vis, "<C-c>", 0, true); >+ continue; > } > > if (vis->resume) { >@@ -1669,7 +1686,7 @@ > size_t newpos = vis_text_insert_nl(vis, txt, pos); > /* This is a bit of a hack to fix cursor positioning when > * inserting a new line at the start of the view port. >- * It has the effect of reseting the mark used by the view >+ * It has the effect of resetting the mark used by the view > * code to keep track of the start of the visible region. > */ > view_cursors_to(s, pos); >@@ -1684,7 +1701,8 @@ > Regex *regex = text_regex_new(); > if (!regex) > return NULL; >- if (text_regex_compile(regex, pattern, REG_EXTENDED|REG_NEWLINE) != 0) { >+ int cflags = REG_EXTENDED|REG_NEWLINE|(REG_ICASE*vis->ignorecase); >+ if (text_regex_compile(regex, pattern, cflags) != 0) { > text_regex_free(regex); > return NULL; > } >@@ -1842,8 +1860,8 @@ > if (len > 0) { > rout.start += len; > if (text_range_size(&rout) == 0) { >- close(pout[1]); >- pout[1] = -1; >+ close(pin[1]); >+ pin[1] = -1; > } > } else { > close(pin[1]); >diff -ur vis-0.6/vis.h vis-0.8/vis.h >--- vis-0.6/vis.h 2020-06-07 13:25:20 >+++ vis-0.8/vis.h 2022-11-01 16:50:10 >@@ -57,6 +57,7 @@ > void (*win_close)(Vis*, Win*); > void (*win_highlight)(Vis*, Win*); > void (*win_status)(Vis*, Win*); >+ void (*term_csi)(Vis*, const long *); > } VisEvent; > > /** Union used to pass arguments to key action functions. */ >@@ -76,7 +77,7 @@ > * @rst > * .. note:: An empty string ``""`` indicates that no further input is available. > * @endrst >- * @return Pointer to first non-cosumed key. >+ * @return Pointer to first non-consumed key. > * @rst > * .. warning:: Must be in range ``[keys, keys+strlen(keys)]`` or ``NULL`` to > * indicate that not enough input was available. In the latter case >@@ -130,7 +131,7 @@ > void vis_die(Vis*, const char *msg, ...) __attribute__((noreturn,format(printf, 2, 3))); > > /** >- * Temporarily supsend the editor process. >+ * Temporarily suspend the editor process. > * @rst > * .. note:: This function will generate a ``SIGTSTP`` signal. > * @endrst >@@ -221,9 +222,9 @@ > void vis_window_focus(Win*); > /** Swap location of two windows. */ > void vis_window_swap(Win*, Win*); >-/** Query window dimension. */ >+/** Query window width. */ > int vis_window_width_get(const Win*); >-/** Query window dimension. */ >+/** Query window height. */ > int vis_window_height_get(const Win*); > /** > * @} >@@ -263,7 +264,7 @@ > /** Perform insertion at all cursor positions. */ > void vis_insert_key(Vis*, const char *data, size_t len); > /** >- * Perform character subsitution at all cursor positions. >+ * Perform character substitution at all cursor positions. > * @rst > * .. note:: Does not replace new line characters. > * @endrst >@@ -432,7 +433,7 @@ > * > * - `VIS_OP_JOIN` a char pointer referring to the text to insert between lines. > * - `VIS_OP_MODESWITCH` an ``enum VisMode`` indicating the mode to switch to. >- * - `VIS_OP_REPLACE` a char pointer reffering to the replacement character. >+ * - `VIS_OP_REPLACE` a char pointer referring to the replacement character. > */ > bool vis_operator(Vis*, enum VisOperator, ...); > >@@ -490,10 +491,14 @@ > VIS_MOVE_PARENTHESIS_START, > VIS_MOVE_PARENTHESIS_END, > VIS_MOVE_BRACKET_MATCH, >- VIS_MOVE_LEFT_TO, >- VIS_MOVE_RIGHT_TO, >- VIS_MOVE_LEFT_TILL, >- VIS_MOVE_RIGHT_TILL, >+ VIS_MOVE_TO_LEFT, >+ VIS_MOVE_TO_RIGHT, >+ VIS_MOVE_TO_LINE_LEFT, >+ VIS_MOVE_TO_LINE_RIGHT, >+ VIS_MOVE_TILL_LEFT, >+ VIS_MOVE_TILL_RIGHT, >+ VIS_MOVE_TILL_LINE_LEFT, >+ VIS_MOVE_TILL_LINE_RIGHT, > VIS_MOVE_FILE_BEGIN, > VIS_MOVE_FILE_END, > VIS_MOVE_SEARCH_WORD_FORWARD, >@@ -622,8 +627,6 @@ > VIS_TEXTOBJECT_INNER_SINGLE_QUOTE, > VIS_TEXTOBJECT_OUTER_BACKTICK, > VIS_TEXTOBJECT_INNER_BACKTICK, >- VIS_TEXTOBJECT_OUTER_ENTIRE, >- VIS_TEXTOBJECT_INNER_ENTIRE, > VIS_TEXTOBJECT_OUTER_LINE, > VIS_TEXTOBJECT_INNER_LINE, > VIS_TEXTOBJECT_INDENTATION, >@@ -675,8 +678,9 @@ > * @defgroup vis_marks > * @{ > */ >-/** Translate single character mark name to corresponding constant. */ >+/** Translate between single character mark name and corresponding constant. */ > enum VisMark vis_mark_from(Vis*, char mark); >+char vis_mark_to(Vis*, enum VisMark); > /** > * Specify mark to use. > * @rst >@@ -731,6 +735,7 @@ > VIS_REG_9, > VIS_REG_BLACKHOLE, /* /dev/null register */ > VIS_REG_CLIPBOARD, /* system clipboard register */ >+ VIS_REG_PRIMARY, /* system primary clipboard register */ > VIS_REG_DOT, /* last inserted text, copy of VIS_MACRO_OPERATOR */ > VIS_REG_SEARCH, /* last used search pattern "/ */ > VIS_REG_COMMAND, /* last used :-command ": */ >@@ -758,8 +763,9 @@ > * @defgroup vis_registers > * @{ > */ >-/** Translate single character register name to corresponding constant. */ >+/** Translate between single character register name and corresponding constant. */ > enum VisRegister vis_register_from(Vis*, char reg); >+char vis_register_to(Vis*, enum VisRegister); > /** > * Specify register to use. > * @rst >@@ -772,7 +778,7 @@ > * Get register content. > * @return An array of ``TextString`` structs. > * @rst >- * .. warning:: The caller must eventually free the array ressources using >+ * .. warning:: The caller must eventually free the array resources using > * ``array_release``. > * @endrst > */ >@@ -851,7 +857,7 @@ > * Option handler function. > * @param win The window to which option should apply, might be ``NULL``. > * @param context User provided context pointer as given to `vis_option_register`. >- * @param force Whether the option was specfied with a bang ``!``. >+ * @param force Whether the option was specified with a bang ``!``. > * @param name Name of option which was set. > * @param arg The new option value. > */ >@@ -962,7 +968,7 @@ > Regex *vis_regex(Vis*, const char *pattern); > > /** >- * Take an undo snaphost to which we can later revert to. >+ * Take an undo snapshot to which we can later revert. > * @rst > * .. note:: Does nothing when invoked while replaying a macro. > * @endrst
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 46325
: 13321 |
13322
|
13367