View | Details | Raw Unified | Return to bug 46325
Collapse All | Expand All

(-)vis-0.6/.github/workflows/coverity-scan.yml (-2 / +7 lines)
Lines 24-32 Link Here
24
24
25
    - name: Download Coverity Build Tool
25
    - name: Download Coverity Build Tool
26
      run: |
26
      run: |
27
        wget -q https://scan.coverity.com/download/cxx/linux64 --post-data "token=$TOKEN&project=martanne/vis" -O cov-analysis-linux64.tar.gz
27
        wget -q https://scan.coverity.com/download/cxx/linux64 --post-data "token=$TOKEN&project=martanne/vis" -O coverity_tool.tgz
28
        wget -q https://scan.coverity.com/download/cxx/linux64 --post-data "token=$TOKEN&project=martanne/vis&md5=1" -O coverity_tool.md5
29
        if ! (cat coverity_tool.md5; echo "  coverity_tool.tgz") | md5sum -c --status; then
30
          echo "Download checksum verification failed"
31
          exit 1
32
        fi
28
        mkdir cov-analysis-linux64
33
        mkdir cov-analysis-linux64
29
        tar xzf cov-analysis-linux64.tar.gz --strip 1 -C cov-analysis-linux64
34
        tar xzf coverity_tool.tgz --strip 1 -C cov-analysis-linux64
30
      env:
35
      env:
31
        TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
36
        TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
32
37
(-)vis-0.6/.github/workflows/macos.yml (-1 / +7 lines)
Lines 49-52 Link Here
49
      env:
49
      env:
50
        CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
50
        CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
51
      run: |
51
      run: |
52
        bash <(curl -s https://codecov.io/bash)
52
        curl -s https://codecov.io/bash > codecov
53
        curl -s https://raw.githubusercontent.com/codecov/codecov-bash/master/SHA256SUM > codecov.sha256
54
        if ! sha256sum -c --ignore-missing --status codecov.sha256 ; then
55
          echo "Download checksum verification failed"
56
          exit 1
57
        fi
58
        bash < codecov
(-)vis-0.6/.github/workflows/ubuntu.yml (-1 / +7 lines)
Lines 55-58 Link Here
55
      env:
55
      env:
56
        CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
56
        CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
57
      run: |
57
      run: |
58
        bash <(curl -s https://codecov.io/bash)
58
        curl -s https://codecov.io/bash > codecov
59
        curl -s https://raw.githubusercontent.com/codecov/codecov-bash/master/SHA256SUM > codecov.sha256
60
        if ! sha256sum -c --ignore-missing --status codecov.sha256 ; then
61
          echo "Download checksum verification failed"
62
          exit 1
63
        fi
64
        bash < codecov
(-)vis-0.6/.github/workflows/windows.yml (-2 / +12 lines)
Lines 21-28 Link Here
21
      run: |
21
      run: |
22
        choco install --no-progress --yes --force --source=cygwin gcc-core,libtool,make,wget,pkg-config
22
        choco install --no-progress --yes --force --source=cygwin gcc-core,libtool,make,wget,pkg-config
23
        choco install --no-progress --yes --force --source=cygwin lua,lua-devel,lua-lpeg,libncurses-devel
23
        choco install --no-progress --yes --force --source=cygwin lua,lua-devel,lua-lpeg,libncurses-devel
24
        echo '::add-path::C:\tools\cygwin\bin'
25
24
25
    - name: Setup $PATH
26
      shell: bash
27
      run: echo 'C:\tools\cygwin\bin' >> $GITHUB_PATH
28
26
    - name: Git configuration
29
    - name: Git configuration
27
      run: |
30
      run: |
28
        git config --global core.autocrlf input
31
        git config --global core.autocrlf input
Lines 51-54 Link Here
51
      shell: bash
54
      shell: bash
52
      env:
55
      env:
53
        CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
56
        CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
54
      run: bash <(curl -s https://codecov.io/bash)
57
      run: |
58
        curl -s https://codecov.io/bash > codecov
59
        curl -s https://raw.githubusercontent.com/codecov/codecov-bash/master/SHA256SUM > codecov.sha256
60
        if ! sha256sum -c --ignore-missing --status codecov.sha256 ; then
61
          echo "Download checksum verification failed"
62
          exit 1
63
        fi
64
        bash < codecov
(-)vis-0.6/.gitignore (-2 lines)
Lines 12-16 Link Here
12
*.gcov
12
*.gcov
13
*.html
13
*.html
14
*.o
14
*.o
15
*.swo
16
*.swp
(-)vis-0.6/Dockerfile (-1 / +1 lines)
Lines 1-5 Link Here
1
# Run 'make docker' to build a statically linked vis executable!
1
# Run 'make docker' to build a statically linked vis executable!
2
FROM i386/alpine:3.12
2
FROM i386/alpine:3.13
3
RUN apk update && apk add --upgrade --no-cache \
3
RUN apk update && apk add --upgrade --no-cache \
4
	acl-dev \
4
	acl-dev \
5
	acl-static \
5
	acl-static \
(-)vis-0.6/LICENSE (-1 / +1 lines)
Lines 1-6 Link Here
1
vis as a whole is licensed under the following standard ISC license:
1
vis as a whole is licensed under the following standard ISC license:
2
2
3
 Copyright © 2014-2018 Marc André Tanner, et al.
3
 Copyright © 2014-2020 Marc André Tanner, et al.
4
4
5
 Permission to use, copy, modify, and/or distribute this software for any
5
 Permission to use, copy, modify, and/or distribute this software for any
6
 purpose with or without fee is hereby granted, provided that the above
6
 purpose with or without fee is hereby granted, provided that the above
(-)vis-0.6/Makefile (-7 / +36 lines)
Lines 2-11 Link Here
2
2
3
REGEX_SRC ?= text-regex.c
3
REGEX_SRC ?= text-regex.c
4
4
5
SRC = array.c buffer.c libutf.c main.c map.c \
5
SRC = array.c \
6
	sam.c text.c text-motions.c text-objects.c text-util.c \
6
	buffer.c \
7
	ui-terminal.c view.c vis.c vis-lua.c vis-modes.c vis-motions.c \
7
	libutf.c \
8
	vis-operators.c vis-registers.c vis-marks.c vis-prompt.c vis-text-objects.c $(REGEX_SRC)
8
	main.c \
9
	map.c \
10
	sam.c \
11
	text.c \
12
	text-common.c \
13
	text-io.c \
14
	text-iterator.c \
15
	text-motions.c \
16
	text-objects.c \
17
	text-util.c \
18
	ui-terminal.c \
19
	view.c \
20
	vis.c \
21
	vis-lua.c \
22
	vis-marks.c \
23
	vis-modes.c \
24
	vis-motions.c \
25
	vis-operators.c \
26
	vis-prompt.c \
27
	vis-registers.c \
28
	vis-text-objects.c \
29
	$(REGEX_SRC)
9
30
10
ELF = vis vis-menu vis-digraph
31
ELF = vis vis-menu vis-digraph
11
EXECUTABLES = $(ELF) vis-clipboard vis-complete vis-open
32
EXECUTABLES = $(ELF) vis-clipboard vis-complete vis-open
Lines 14-20 Link Here
14
35
15
DOCUMENTATION = LICENSE README.md
36
DOCUMENTATION = LICENSE README.md
16
37
17
VERSION = v0.6
38
VERSION = 0.8
18
39
19
CONFIG_HELP ?= 1
40
CONFIG_HELP ?= 1
20
CONFIG_CURSES ?= 1
41
CONFIG_CURSES ?= 1
Lines 121-131 Link Here
121
	[ -e test/Makefile ] || $(MAKE) test-update
142
	[ -e test/Makefile ] || $(MAKE) test-update
122
	@$(MAKE) -C test
143
	@$(MAKE) -C test
123
144
145
testclean:
146
	@echo cleaning the test artifacts
147
	[ ! -e test/Makefile ] || $(MAKE) -C test clean
148
124
clean:
149
clean:
125
	@echo cleaning
150
	@echo cleaning
126
	@rm -f $(ELF) vis-single vis-single-payload.inc vis-*.tar.gz *.gcov *.gcda *.gcno
151
	@rm -f $(ELF) vis-single vis-single-payload.inc vis-*.tar.gz *.gcov *.gcda *.gcno
127
152
128
dist: clean
153
distclean: clean testclean
154
	@echo cleaning build configuration
155
	@rm -f config.h config.mk
156
157
dist: distclean
129
	@echo creating dist tarball
158
	@echo creating dist tarball
130
	@git archive --prefix=vis-${VERSION}/ -o vis-${VERSION}.tar.gz HEAD
159
	@git archive --prefix=vis-${VERSION}/ -o vis-${VERSION}.tar.gz HEAD
131
160
Lines 192-195 Link Here
192
	@echo removing support files from ${DESTDIR}${SHAREPREFIX}/vis
221
	@echo removing support files from ${DESTDIR}${SHAREPREFIX}/vis
193
	@rm -rf ${DESTDIR}${SHAREPREFIX}/vis
222
	@rm -rf ${DESTDIR}${SHAREPREFIX}/vis
194
223
195
.PHONY: all clean dist install install-strip uninstall debug profile coverage test test-update luadoc luadoc-all luacheck man docker-kill docker docker-clean
224
.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
(-)vis-0.6/README.md (-5 / +5 lines)
Lines 1-10 Link Here
1
# Vis - Combining Modal Editing with Structural Regular Expressions
1
# Vis - Combining Modal Editing with Structural Regular Expressions
2
2
3
[![builds.sr.ht status](https://builds.sr.ht/~martanne/vis.svg)](https://builds.sr.ht/~martanne/vis)
3
[![builds.sr.ht status](https://builds.sr.ht/~martanne/vis/commits.svg)](https://builds.sr.ht/~martanne/vis/commits?)
4
[![Coverity Scan Build Status](https://scan.coverity.com/projects/3939/badge.svg)](https://scan.coverity.com/projects/3939)
4
[![Coverity Scan Build Status](https://scan.coverity.com/projects/3939/badge.svg)](https://scan.coverity.com/projects/3939)
5
[![codecov](https://codecov.io/gh/martanne/vis/branch/master/graph/badge.svg)](https://codecov.io/gh/martanne/vis)
5
[![codecov](https://codecov.io/gh/martanne/vis/branch/master/graph/badge.svg)](https://codecov.io/gh/martanne/vis)
6
[![Documentation Status](https://readthedocs.org/projects/vis/badge/?version=master)](http://vis.readthedocs.io/en/master/?badge=master)
6
[![Documentation Status](https://readthedocs.org/projects/vis/badge/?version=master)](http://vis.readthedocs.io/en/master/?badge=master)
7
[![#vis-editor on freenode](https://img.shields.io/badge/IRC-%23vis--editor-blue.svg)](irc://irc.freenode.net/vis-editor)
7
[![#vis-editor on libera](https://img.shields.io/badge/IRC-%23vis--editor-blue.svg)](ircs://irc.libera.chat:6697/vis-editor)
8
8
9
Vis aims to be a modern, legacy-free, simple yet efficient editor,
9
Vis aims to be a modern, legacy-free, simple yet efficient editor,
10
combining the strengths of both vi(m) and sam.
10
combining the strengths of both vi(m) and sam.
Lines 60-67 Link Here
60
    $ ./configure && make && sudo make install
60
    $ ./configure && make && sudo make install
61
61
62
By default the `configure` script will try to auto detect support for
62
By default the `configure` script will try to auto detect support for
63
Lua. See `configure --help` for a list of supported options. You can
63
Lua using `pkg-config(1)`. See `configure --help` for a list of supported
64
also manually tweak the generated `config.mk` file.
64
options. You can also manually tweak the generated `config.mk` file.
65
65
66
Or simply use one of the
66
Or simply use one of the
67
[distribution provided packages](https://github.com/martanne/vis/wiki/Distribution-Packages).
67
[distribution provided packages](https://github.com/martanne/vis/wiki/Distribution-Packages).
Lines 127-130 Link Here
127
127
128
Checkout the [Developer Overview](https://github.com/martanne/vis/wiki/Developer-Overview)
128
Checkout the [Developer Overview](https://github.com/martanne/vis/wiki/Developer-Overview)
129
to get started and do not hesitate to ask question in the `#vis-editor`
129
to get started and do not hesitate to ask question in the `#vis-editor`
130
IRC channel on freenode.
130
IRC channel on libera ([join via your browser](https://web.libera.chat/#vis-editor)).
(-)vis-0.6/array.c (-6 / +6 lines)
Lines 11-17 Link Here
11
	array_init_sized(arr, sizeof(void*));
11
	array_init_sized(arr, sizeof(void*));
12
}
12
}
13
13
14
void array_init_from(Array *arr, Array *from) {
14
void array_init_from(Array *arr, const Array *from) {
15
	array_init_sized(arr, from->elem_size);
15
	array_init_sized(arr, from->elem_size);
16
}
16
}
17
17
Lines 55-61 Link Here
55
		memset(arr->items, 0, arr->count * arr->elem_size);
55
		memset(arr->items, 0, arr->count * arr->elem_size);
56
}
56
}
57
57
58
void *array_get(Array *arr, size_t idx) {
58
void *array_get(const Array *arr, size_t idx) {
59
	if (idx >= arr->len) {
59
	if (idx >= arr->len) {
60
		errno = EINVAL;
60
		errno = EINVAL;
61
		return NULL;
61
		return NULL;
Lines 63-69 Link Here
63
	return arr->items + (idx * arr->elem_size);
63
	return arr->items + (idx * arr->elem_size);
64
}
64
}
65
65
66
void *array_get_ptr(Array *arr, size_t idx) {
66
void *array_get_ptr(const Array *arr, size_t idx) {
67
	if (arr->elem_size != sizeof(void*)) {
67
	if (arr->elem_size != sizeof(void*)) {
68
		errno = ENOTSUP;
68
		errno = ENOTSUP;
69
		return NULL;
69
		return NULL;
Lines 124-134 Link Here
124
	return true;
124
	return true;
125
}
125
}
126
126
127
size_t array_length(Array *arr) {
127
size_t array_length(const Array *arr) {
128
	return arr->len;
128
	return arr->len;
129
}
129
}
130
130
131
size_t array_capacity(Array *arr) {
131
size_t array_capacity(const Array *arr) {
132
	return arr->count;
132
	return arr->count;
133
}
133
}
134
134
Lines 165-171 Link Here
165
	return item;
165
	return item;
166
}
166
}
167
167
168
void *array_peek(Array *arr) {
168
void *array_peek(const Array *arr) {
169
	if (arr->len == 0)
169
	if (arr->len == 0)
170
		return NULL;
170
		return NULL;
171
	return array_get(arr, arr->len - 1);
171
	return array_get(arr, arr->len - 1);
(-)vis-0.6/array.h (-7 / +7 lines)
Lines 44-50 Link Here
44
 */
44
 */
45
void array_init_sized(Array*, size_t elem_size);
45
void array_init_sized(Array*, size_t elem_size);
46
/** Initialize Array by using the same element size as in ``from``. */
46
/** Initialize Array by using the same element size as in ``from``. */
47
void array_init_from(Array*, Array *from);
47
void array_init_from(Array*, const Array *from);
48
/** Release storage space. Reinitializes Array object. */
48
/** Release storage space. Reinitializes Array object. */
49
void array_release(Array*);
49
void array_release(Array*);
50
/**
50
/**
Lines 66-72 Link Here
66
 *              of new elements) might invalidate the pointer.
66
 *              of new elements) might invalidate the pointer.
67
 * @endrst
67
 * @endrst
68
 */
68
 */
69
void *array_get(Array*, size_t idx);
69
void *array_get(const Array*, size_t idx);
70
/**
70
/**
71
 * Set array element.
71
 * Set array element.
72
 * @rst
72
 * @rst
Lines 76-82 Link Here
76
 */
76
 */
77
bool array_set(Array*, size_t idx, void *item);
77
bool array_set(Array*, size_t idx, void *item);
78
/** Dereference pointer stored in array element. */
78
/** Dereference pointer stored in array element. */
79
void *array_get_ptr(Array*, size_t idx);
79
void *array_get_ptr(const Array*, size_t idx);
80
/** Store the address to which ``item`` points to into the array. */
80
/** Store the address to which ``item`` points to into the array. */
81
bool array_set_ptr(Array*, size_t idx, void *item);
81
bool array_set_ptr(Array*, size_t idx, void *item);
82
/** Add element to the end of the array. */
82
/** Add element to the end of the array. */
Lines 91-106 Link Here
91
 */
91
 */
92
bool array_remove(Array*, size_t idx);
92
bool array_remove(Array*, size_t idx);
93
/** Number of elements currently stored in the array. */
93
/** Number of elements currently stored in the array. */
94
size_t array_length(Array*);
94
size_t array_length(const Array*);
95
/** Number of elements which can be stored without enlarging the array. */
95
/** Number of elements which can be stored without enlarging the array. */
96
size_t array_capacity(Array*);
96
size_t array_capacity(const Array*);
97
/** Remove all elements with index greater or equal to ``length``, keep allocated memory. */
97
/** Remove all elements with index greater or equal to ``length``, keep allocated memory. */
98
bool array_truncate(Array*, size_t length);
98
bool array_truncate(Array*, size_t length);
99
/**
99
/**
100
 * Change length.
100
 * Change length.
101
 * @rst
101
 * @rst
102
 * .. note:: Has to be less or equal than the capacity.
102
 * .. note:: Has to be less or equal than the capacity.
103
 *           Newly accesible elements preserve their previous values.
103
 *           Newly accessible elements preserve their previous values.
104
 * @endrst
104
 * @endrst
105
 */
105
 */
106
bool array_resize(Array*, size_t length);
106
bool array_resize(Array*, size_t length);
Lines 128-133 Link Here
128
 * .. warning:: The same ownership rules as for ``array_get`` apply.
128
 * .. warning:: The same ownership rules as for ``array_get`` apply.
129
 * @endrst
129
 * @endrst
130
 */
130
 */
131
void *array_peek(Array*);
131
void *array_peek(const Array*);
132
132
133
#endif
133
#endif
(-)vis-0.6/buffer.h (-4 / +4 lines)
Lines 44-54 Link Here
44
bool buffer_insert0(Buffer*, size_t pos, const char *data);
44
bool buffer_insert0(Buffer*, size_t pos, const char *data);
45
/** Append further content to the end. */
45
/** Append further content to the end. */
46
bool buffer_append(Buffer*, const void *data, size_t len);
46
bool buffer_append(Buffer*, const void *data, size_t len);
47
/** Append NUl-terminated data. */
47
/** Append NUL-terminated data. */
48
bool buffer_append0(Buffer*, const char *data);
48
bool buffer_append0(Buffer*, const char *data);
49
/** Insert ``len`` bytes of ``data`` at the begin. */
49
/** Insert ``len`` bytes of ``data`` at the start. */
50
bool buffer_prepend(Buffer*, const void *data, size_t len);
50
bool buffer_prepend(Buffer*, const void *data, size_t len);
51
/** Insert NUL-terminated data at the begin. */
51
/** Insert NUL-terminated data at the start. */
52
bool buffer_prepend0(Buffer*, const char *data);
52
bool buffer_prepend0(Buffer*, const char *data);
53
/** Set formatted buffer content, ensures NUL termination on success. */
53
/** Set formatted buffer content, ensures NUL termination on success. */
54
bool buffer_printf(Buffer*, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
54
bool buffer_printf(Buffer*, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
Lines 75-81 Link Here
75
/**
75
/**
76
 * Borrow underlying buffer data.
76
 * Borrow underlying buffer data.
77
 * @rst
77
 * @rst
78
 * .. warning:: The caller is responsible to `free(3)` it.
78
 * .. warning:: The caller is responsible to ``free(3)`` it.
79
 * @endrst
79
 * @endrst
80
 */
80
 */
81
char *buffer_move(Buffer*);
81
char *buffer_move(Buffer*);
(-)vis-0.6/config.def.h (-36 / +9 lines)
Lines 45-64 Link Here
45
	{ ",",                  ACTION(TOTILL_REVERSE)                      },
45
	{ ",",                  ACTION(TOTILL_REVERSE)                      },
46
	{ "+",                  ALIAS("j^")                                 },
46
	{ "+",                  ALIAS("j^")                                 },
47
	{ "-",                  ALIAS("k^")                                 },
47
	{ "-",                  ALIAS("k^")                                 },
48
	{ " ",                  ALIAS("<Space>")                            },
49
	{ "<Space>",            ALIAS("l")                                  },
50
	{ "<Backspace>",        ALIAS("h")                                  },
51
	{ "B",                  ACTION(CURSOR_LONGWORD_START_PREV)          },
48
	{ "B",                  ACTION(CURSOR_LONGWORD_START_PREV)          },
52
	{ "b",                  ACTION(CURSOR_WORD_START_PREV)              },
49
	{ "b",                  ACTION(CURSOR_WORD_START_PREV)              },
53
	{ "<C-h>",              ALIAS("<Backspace>")                        },
54
	{ "<C-j>",              ALIAS("j")                                  },
55
	{ "<C-n>",              ALIAS("j")                                  },
56
	{ "<C-p>",              ALIAS("k")                                  },
57
	{ "E",                  ACTION(CURSOR_LONGWORD_END_NEXT)            },
50
	{ "E",                  ACTION(CURSOR_LONGWORD_END_NEXT)            },
58
	{ "e",                  ACTION(CURSOR_WORD_END_NEXT)                },
51
	{ "e",                  ACTION(CURSOR_WORD_END_NEXT)                },
59
	{ "<Enter>",            ALIAS("j")                                  },
52
	{ "F",                  ACTION(TO_LINE_LEFT)                        },
60
	{ "F",                  ACTION(TO_LEFT)                             },
53
	{ "f",                  ACTION(TO_LINE_RIGHT)                       },
61
	{ "f",                  ACTION(TO_RIGHT)                            },
62
	{ "go",                 ACTION(CURSOR_BYTE)                         },
54
	{ "go",                 ACTION(CURSOR_BYTE)                         },
63
	{ "gH",                 ACTION(CURSOR_BYTE_LEFT)                    },
55
	{ "gH",                 ACTION(CURSOR_BYTE_LEFT)                    },
64
	{ "gL",                 ACTION(CURSOR_BYTE_RIGHT)                   },
56
	{ "gL",                 ACTION(CURSOR_BYTE_RIGHT)                   },
Lines 83-90 Link Here
83
	{ "M",                  ACTION(CURSOR_WINDOW_LINE_MIDDLE)           },
75
	{ "M",                  ACTION(CURSOR_WINDOW_LINE_MIDDLE)           },
84
	{ "n",                  ACTION(CURSOR_SEARCH_REPEAT_FORWARD)        },
76
	{ "n",                  ACTION(CURSOR_SEARCH_REPEAT_FORWARD)        },
85
	{ "N",                  ACTION(CURSOR_SEARCH_REPEAT_BACKWARD)       },
77
	{ "N",                  ACTION(CURSOR_SEARCH_REPEAT_BACKWARD)       },
86
	{ "T",                  ACTION(TILL_LEFT)                           },
78
	{ "T",                  ACTION(TILL_LINE_LEFT)                      },
87
	{ "t",                  ACTION(TILL_RIGHT)                          },
79
	{ "t",                  ACTION(TILL_LINE_RIGHT)                     },
88
	{ "W",                  ACTION(CURSOR_LONGWORD_START_NEXT)          },
80
	{ "W",                  ACTION(CURSOR_LONGWORD_START_NEXT)          },
89
	{ "w",                  ACTION(CURSOR_WORD_START_NEXT)              },
81
	{ "w",                  ACTION(CURSOR_WORD_START_NEXT)              },
90
	{ 0 /* empty last element, array terminator */                      },
82
	{ 0 /* empty last element, array terminator */                      },
Lines 104-110 Link Here
104
	{ "a}",                 ALIAS("a{")                                 },
96
	{ "a}",                 ALIAS("a{")                                 },
105
	{ "ab",                 ALIAS("a(")                                 },
97
	{ "ab",                 ALIAS("a(")                                 },
106
	{ "aB",                 ALIAS("a{")                                 },
98
	{ "aB",                 ALIAS("a{")                                 },
107
	{ "ae",                 ACTION(TEXT_OBJECT_ENTIRE_OUTER)            },
108
	{ "al",                 ACTION(TEXT_OBJECT_LINE_OUTER)              },
99
	{ "al",                 ACTION(TEXT_OBJECT_LINE_OUTER)              },
109
	{ "ap",                 ACTION(TEXT_OBJECT_PARAGRAPH_OUTER)         },
100
	{ "ap",                 ACTION(TEXT_OBJECT_PARAGRAPH_OUTER)         },
110
	{ "as",                 ACTION(TEXT_OBJECT_SENTENCE)                },
101
	{ "as",                 ACTION(TEXT_OBJECT_SENTENCE)                },
Lines 126-132 Link Here
126
	{ "i}",                 ALIAS("i{")                                 },
117
	{ "i}",                 ALIAS("i{")                                 },
127
	{ "ib",                 ALIAS("i(")                                 },
118
	{ "ib",                 ALIAS("i(")                                 },
128
	{ "iB",                 ALIAS("i{")                                 },
119
	{ "iB",                 ALIAS("i{")                                 },
129
	{ "ie",                 ACTION(TEXT_OBJECT_ENTIRE_INNER)            },
130
	{ "il",                 ACTION(TEXT_OBJECT_LINE_INNER)              },
120
	{ "il",                 ACTION(TEXT_OBJECT_LINE_INNER)              },
131
	{ "ip",                 ACTION(TEXT_OBJECT_PARAGRAPH)               },
121
	{ "ip",                 ACTION(TEXT_OBJECT_PARAGRAPH)               },
132
	{ "is",                 ACTION(TEXT_OBJECT_SENTENCE)                },
122
	{ "is",                 ACTION(TEXT_OBJECT_SENTENCE)                },
Lines 141-156 Link Here
141
	{ "M",                  ACTION(SELECTIONS_RESTORE)                  },
131
	{ "M",                  ACTION(SELECTIONS_RESTORE)                  },
142
	{ "|",                  ACTION(SELECTIONS_UNION)                    },
132
	{ "|",                  ACTION(SELECTIONS_UNION)                    },
143
	{ "&",                  ACTION(SELECTIONS_INTERSECT)                },
133
	{ "&",                  ACTION(SELECTIONS_INTERSECT)                },
144
	{ "!",                  ACTION(SELECTIONS_COMPLEMENT)               },
134
	{ "~",                  ACTION(SELECTIONS_COMPLEMENT)               },
145
	{ "\\",                 ACTION(SELECTIONS_MINUS)                    },
135
	{ "\\",                 ACTION(SELECTIONS_MINUS)                    },
146
	{ "z|",                 ACTION(SELECTIONS_COMBINE_UNION)            },
147
	{ "z&",                 ACTION(SELECTIONS_COMBINE_INTERSECT)        },
148
	{ "z+",                 ACTION(SELECTIONS_COMBINE_LONGER)           },
149
	{ "z-",                 ACTION(SELECTIONS_COMBINE_SHORTER)          },
150
	{ "z<",                 ACTION(SELECTIONS_COMBINE_LEFTMOST)         },
151
	{ "z>",                 ACTION(SELECTIONS_COMBINE_RIGHTMOST)        },
152
//	{ "-",                  ACTION(SELECTIONS_ROTATE_LEFT)              },
153
//	{ "+",                  ACTION(SELECTIONS_ROTATE_RIGHT)             },
154
	{ "_",                  ACTION(SELECTIONS_TRIM)                     },
136
	{ "_",                  ACTION(SELECTIONS_TRIM)                     },
155
	{ "<S-Tab>",            ACTION(SELECTIONS_ALIGN_INDENT_RIGHT)       },
137
	{ "<S-Tab>",            ACTION(SELECTIONS_ALIGN_INDENT_RIGHT)       },
156
	{ "<Tab>",              ACTION(SELECTIONS_ALIGN_INDENT_LEFT)        },
138
	{ "<Tab>",              ACTION(SELECTIONS_ALIGN_INDENT_LEFT)        },
Lines 171-177 Link Here
171
	{ "7",                  ACTION(COUNT)                               },
153
	{ "7",                  ACTION(COUNT)                               },
172
	{ "8",                  ACTION(COUNT)                               },
154
	{ "8",                  ACTION(COUNT)                               },
173
	{ "9",                  ACTION(COUNT)                               },
155
	{ "9",                  ACTION(COUNT)                               },
174
	{ "~",                  ALIAS("g~")                                 },
175
	{ "=",                  ALIAS(":|fmt<Enter>")                       },
156
	{ "=",                  ALIAS(":|fmt<Enter>")                       },
176
	{ "<",                  ACTION(OPERATOR_SHIFT_LEFT)                 },
157
	{ "<",                  ACTION(OPERATOR_SHIFT_LEFT)                 },
177
	{ ">",                  ACTION(OPERATOR_SHIFT_RIGHT)                },
158
	{ ">",                  ACTION(OPERATOR_SHIFT_RIGHT)                },
Lines 203-219 Link Here
203
	{ "<C-j>",              ACTION(SELECTIONS_NEW_LINE_BELOW)           },
184
	{ "<C-j>",              ACTION(SELECTIONS_NEW_LINE_BELOW)           },
204
	{ "<C-k>",              ACTION(SELECTIONS_NEW_LINE_ABOVE)           },
185
	{ "<C-k>",              ACTION(SELECTIONS_NEW_LINE_ABOVE)           },
205
	{ "<C-l>",              ACTION(SELECTIONS_REMOVE_COLUMN_EXCEPT)     },
186
	{ "<C-l>",              ACTION(SELECTIONS_REMOVE_COLUMN_EXCEPT)     },
206
	{ "<C-n>",              ACTION(SELECTIONS_MATCH_WORD)               },
187
	{ "<C-n>",              ALIAS("viw")                                },
207
	{ "<C-p>",              ACTION(SELECTIONS_REMOVE_LAST)              },
188
	{ "<C-p>",              ACTION(SELECTIONS_REMOVE_LAST)              },
208
	{ "<C-r>",              ACTION(REDO)                                },
189
	{ "<C-r>",              ACTION(REDO)                                },
209
	{ "<C-u>",              ACTION(SELECTIONS_PREV)                     },
190
	{ "<C-u>",              ACTION(SELECTIONS_PREV)                     },
210
	{ "<C-w><Backspace>",   ALIAS("<C-w>k")                             },
211
	{ "<C-w>c",             ALIAS(":q<Enter>")                          },
191
	{ "<C-w>c",             ALIAS(":q<Enter>")                          },
212
	{ "<C-w><C-h>",         ALIAS("<C-w>k")                             },
213
	{ "<C-w><C-j>",         ALIAS("<C-w>j")                             },
214
	{ "<C-w><C-k>",         ALIAS("<C-w>k")                             },
215
	{ "<C-w><C-l>",         ALIAS("<C-w>j")                             },
216
	{ "<C-w><C-w>",         ALIAS("<C-w>j")                             },
217
	{ "<C-w>h",             ALIAS("<C-w>k")                             },
192
	{ "<C-w>h",             ALIAS("<C-w>k")                             },
218
	{ "<C-w>j",             ACTION(WINDOW_NEXT)                         },
193
	{ "<C-w>j",             ACTION(WINDOW_NEXT)                         },
219
	{ "<C-w>k",             ACTION(WINDOW_PREV)                         },
194
	{ "<C-w>k",             ACTION(WINDOW_PREV)                         },
Lines 221-230 Link Here
221
	{ "<C-w>n",             ALIAS(":open<Enter>")                       },
196
	{ "<C-w>n",             ALIAS(":open<Enter>")                       },
222
	{ "<C-w>s",             ALIAS(":split<Enter>")                      },
197
	{ "<C-w>s",             ALIAS(":split<Enter>")                      },
223
	{ "<C-w>v",             ALIAS(":vsplit<Enter>")                     },
198
	{ "<C-w>v",             ALIAS(":vsplit<Enter>")                     },
224
	{ "<C-w>w",             ALIAS("<C-w>j")                             },
225
	{ "<C-y>",              ACTION(WINDOW_SLIDE_DOWN)                   },
199
	{ "<C-y>",              ACTION(WINDOW_SLIDE_DOWN)                   },
226
	{ "D",                  ALIAS("d$")                                 },
200
	{ "D",                  ALIAS("d$")                                 },
227
	{ "<Delete>",           ALIAS("x")                                  },
228
	{ "<Escape>",           ACTION(MODE_NORMAL_ESCAPE)                  },
201
	{ "<Escape>",           ACTION(MODE_NORMAL_ESCAPE)                  },
229
	{ "<F1>",               ALIAS(":help<Enter>")                       },
202
	{ "<F1>",               ALIAS(":help<Enter>")                       },
230
	{ "ga",                 ACTION(UNICODE_INFO)                        },
203
	{ "ga",                 ACTION(UNICODE_INFO)                        },
Lines 270-281 Link Here
270
	{ "+",                  ACTION(SELECTIONS_ROTATE_RIGHT)             },
243
	{ "+",                  ACTION(SELECTIONS_ROTATE_RIGHT)             },
271
	{ "<",                  ALIAS("<vis-operator-shift-left>gv")        },
244
	{ "<",                  ALIAS("<vis-operator-shift-left>gv")        },
272
	{ ">",                  ALIAS("<vis-operator-shift-right>gv")       },
245
	{ ">",                  ALIAS("<vis-operator-shift-right>gv")       },
273
	{ "<Backspace>",        ALIAS("d")                                  },
246
	{ "<C-a>",              ACTION(SELECTIONS_NEW_MATCH_ALL)            },
274
	{ "<C-b>",              ALIAS("<PageUp>")                           },
247
	{ "<C-b>",              ALIAS("<PageUp>")                           },
275
	{ "<C-c>",              ACTION(SELECTIONS_REMOVE_COLUMN)            },
248
	{ "<C-c>",              ACTION(SELECTIONS_REMOVE_COLUMN)            },
276
	{ "<C-d>",              ACTION(SELECTIONS_NEXT)                     },
249
	{ "<C-d>",              ACTION(SELECTIONS_NEXT)                     },
277
	{ "<C-f>",              ALIAS("<PageDown>")                         },
250
	{ "<C-f>",              ALIAS("<PageDown>")                         },
278
	{ "<C-h>",              ALIAS("<Backspace>")                        },
279
	{ "<C-j>",              ALIAS("<C-d>")                              },
251
	{ "<C-j>",              ALIAS("<C-d>")                              },
280
	{ "<C-k>",              ALIAS("<C-u>")                              },
252
	{ "<C-k>",              ALIAS("<C-u>")                              },
281
	{ "<C-l>",              ACTION(SELECTIONS_REMOVE_COLUMN_EXCEPT)     },
253
	{ "<C-l>",              ACTION(SELECTIONS_REMOVE_COLUMN_EXCEPT)     },
Lines 283-289 Link Here
283
	{ "<C-p>",              ACTION(SELECTIONS_REMOVE_LAST)              },
255
	{ "<C-p>",              ACTION(SELECTIONS_REMOVE_LAST)              },
284
	{ "<C-u>",              ACTION(SELECTIONS_PREV)                     },
256
	{ "<C-u>",              ACTION(SELECTIONS_PREV)                     },
285
	{ "<C-x>",              ACTION(SELECTIONS_NEW_MATCH_SKIP)           },
257
	{ "<C-x>",              ACTION(SELECTIONS_NEW_MATCH_SKIP)           },
286
	{ "<Delete>",           ALIAS("<Backspace>")                        },
287
	{ "<Escape>",           ACTION(MODE_VISUAL_ESCAPE)                  },
258
	{ "<Escape>",           ACTION(MODE_VISUAL_ESCAPE)                  },
288
	{ "I",                  ACTION(SELECTIONS_NEW_LINES_BEGIN)          },
259
	{ "I",                  ACTION(SELECTIONS_NEW_LINES_BEGIN)          },
289
	{ "J",                  ACTION(JOIN_LINES)                          },
260
	{ "J",                  ACTION(JOIN_LINES)                          },
Lines 314-319 Link Here
314
	{ "<C-u>",              ACTION(DELETE_LINE_BEGIN)                   },
285
	{ "<C-u>",              ACTION(DELETE_LINE_BEGIN)                   },
315
	{ "<C-v>",              ACTION(INSERT_VERBATIM)                     },
286
	{ "<C-v>",              ACTION(INSERT_VERBATIM)                     },
316
	{ "<C-w>",              ACTION(DELETE_WORD_PREV)                    },
287
	{ "<C-w>",              ACTION(DELETE_WORD_PREV)                    },
288
	{ "<C-e>",              ACTION(CURSOR_LINE_END)                     },
289
	{ "<C-a>",              ACTION(CURSOR_LINE_START)                   },
317
	{ "<Delete>",           ACTION(DELETE_CHAR_NEXT)                    },
290
	{ "<Delete>",           ACTION(DELETE_CHAR_NEXT)                    },
318
	{ "<Escape>",           ACTION(MODE_NORMAL)                         },
291
	{ "<Escape>",           ACTION(MODE_NORMAL)                         },
319
	{ 0 /* empty last element, array terminator */                      },
292
	{ 0 /* empty last element, array terminator */                      },
(-)vis-0.6/configure (-4 / +5 lines)
Lines 227-232 Link Here
227
227
228
case "$OS" in
228
case "$OS" in
229
FreeBSD|DragonFly) CFLAGS_STD="$CFLAGS_STD -D_BSD_SOURCE -D__BSD_VISIBLE=1" ;;
229
FreeBSD|DragonFly) CFLAGS_STD="$CFLAGS_STD -D_BSD_SOURCE -D__BSD_VISIBLE=1" ;;
230
NetBSD)  CFLAGS_STD="$CFLAGS_STD -D_NETBSD_SOURCE" ;;
230
*BSD)    CFLAGS_STD="$CFLAGS_STD -D_BSD_SOURCE" ;;
231
*BSD)    CFLAGS_STD="$CFLAGS_STD -D_BSD_SOURCE" ;;
231
Darwin)  CFLAGS_STD="$CFLAGS_STD -D_DARWIN_C_SOURCE" ;;
232
Darwin)  CFLAGS_STD="$CFLAGS_STD -D_DARWIN_C_SOURCE" ;;
232
AIX)     CFLAGS_STD="$CFLAGS_STD -D_ALL_SOURCE" ;;
233
AIX)     CFLAGS_STD="$CFLAGS_STD -D_ALL_SOURCE" ;;
Lines 309-315 Link Here
309
}
310
}
310
EOF
311
EOF
311
312
312
	for libcurses in ncursesw ncurses libcurses; do
313
	for libcurses in ncursesw ncurses curses; do
313
		printf " checking for %s... " "$libcurses"
314
		printf " checking for %s... " "$libcurses"
314
315
315
		if test "$have_pkgconfig" = "yes" ; then
316
		if test "$have_pkgconfig" = "yes" ; then
Lines 442-448 Link Here
442
}
443
}
443
EOF
444
EOF
444
445
445
	for liblua in lua lua5.3 lua5.2 lua-5.3 lua-5.2 lua53 lua52; do
446
	for liblua in lua lua5.4 lua5.3 lua5.2 lua-5.3 lua-5.2 lua54 lua53 lua52; do
446
		printf " checking for %s... " "$liblua"
447
		printf " checking for %s... " "$liblua"
447
448
448
		if test "$have_pkgconfig" = "yes" ; then
449
		if test "$have_pkgconfig" = "yes" ; then
Lines 474-480 Link Here
474
	test "$lua" = "yes" -a $CONFIG_LUA -ne 1 && fail "$0: cannot find liblua"
475
	test "$lua" = "yes" -a $CONFIG_LUA -ne 1 && fail "$0: cannot find liblua"
475
476
476
	if test $CONFIG_LUA -eq 1; then
477
	if test $CONFIG_LUA -eq 1; then
477
		CFLAGS_LUA="$CFLAGS_LUA -DLUA_COMPAT_5_1 -DLUA_COMPAT_5_2 -DLUA_COMPAT_ALL"
478
		CFLAGS_LUA="$CFLAGS_LUA -DLUA_COMPAT_5_1 -DLUA_COMPAT_5_2 -DLUA_COMPAT_5_3 -DLUA_COMPAT_ALL"
478
	fi
479
	fi
479
fi
480
fi
480
481
Lines 618-624 Link Here
618
}
619
}
619
EOF
620
EOF
620
621
621
if $CC $CFLAGS "$tmpc" $LDFLAGS -o "$tmpo" >/dev/null 2>&1; then
622
if $CC $CFLAGS $CFLAGS_STD "$tmpc" $LDFLAGS -o "$tmpo" >/dev/null 2>&1; then
622
	HAVE_MEMRCHR=1
623
	HAVE_MEMRCHR=1
623
	printf "%s\n" "yes"
624
	printf "%s\n" "yes"
624
else
625
else
(-)vis-0.6/doc/Doxyfile (-81 / +158 lines)
Lines 1-4 Link Here
1
# Doxyfile 1.8.13
1
# Doxyfile 1.8.18
2
2
3
# This file describes the settings to be used by the documentation system
3
# This file describes the settings to be used by the documentation system
4
# doxygen (www.doxygen.org) for a project.
4
# doxygen (www.doxygen.org) for a project.
Lines 17-27 Link Here
17
# Project related configuration options
17
# Project related configuration options
18
#---------------------------------------------------------------------------
18
#---------------------------------------------------------------------------
19
19
20
# This tag specifies the encoding used for all characters in the config file
20
# This tag specifies the encoding used for all characters in the configuration
21
# that follow. The default is UTF-8 which is also the encoding used for all text
21
# file that follow. The default is UTF-8 which is also the encoding used for all
22
# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
22
# text before the first occurrence of this tag. Doxygen uses libiconv (or the
23
# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
23
# iconv built into libc) for the transcoding. See
24
# for the list of possible encodings.
24
# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
25
# The default value is: UTF-8.
25
# The default value is: UTF-8.
26
26
27
DOXYFILE_ENCODING      = UTF-8
27
DOXYFILE_ENCODING      = UTF-8
Lines 38-44 Link Here
38
# could be handy for archiving the generated documentation or if some version
38
# could be handy for archiving the generated documentation or if some version
39
# control system is used.
39
# control system is used.
40
40
41
PROJECT_NUMBER         = 0.5
41
PROJECT_NUMBER         = 0.8
42
42
43
# Using the PROJECT_BRIEF tag one can provide an optional one line description
43
# Using the PROJECT_BRIEF tag one can provide an optional one line description
44
# for a project that appears at the top of each page and should give viewer a
44
# for a project that appears at the top of each page and should give viewer a
Lines 93-98 Link Here
93
93
94
OUTPUT_LANGUAGE        = English
94
OUTPUT_LANGUAGE        = English
95
95
96
# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all
97
# documentation generated by doxygen is written. Doxygen will use this
98
# information to generate all generated output in the proper direction.
99
# Possible values are: None, LTR, RTL and Context.
100
# The default value is: None.
101
102
OUTPUT_TEXT_DIRECTION  = None
103
96
# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
104
# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
97
# descriptions after the members that are listed in the file and class
105
# descriptions after the members that are listed in the file and class
98
# documentation (similar to Javadoc). Set to NO to disable this.
106
# documentation (similar to Javadoc). Set to NO to disable this.
Lines 189-194 Link Here
189
197
190
JAVADOC_AUTOBRIEF      = YES
198
JAVADOC_AUTOBRIEF      = YES
191
199
200
# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line
201
# such as
202
# /***************
203
# as being the beginning of a Javadoc-style comment "banner". If set to NO, the
204
# Javadoc-style will behave just like regular comments and it will not be
205
# interpreted by doxygen.
206
# The default value is: NO.
207
208
JAVADOC_BANNER         = NO
209
192
# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
210
# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
193
# line (until the first dot) of a Qt-style comment as the brief description. If
211
# line (until the first dot) of a Qt-style comment as the brief description. If
194
# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
212
# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
Lines 236-252 Link Here
236
# will allow you to put the command \sideeffect (or @sideeffect) in the
254
# will allow you to put the command \sideeffect (or @sideeffect) in the
237
# documentation, which will result in a user-defined paragraph with heading
255
# documentation, which will result in a user-defined paragraph with heading
238
# "Side Effects:". You can put \n's in the value part of an alias to insert
256
# "Side Effects:". You can put \n's in the value part of an alias to insert
239
# newlines.
257
# newlines (in the resulting output). You can put ^^ in the value part of an
258
# alias to insert a newline as if a physical newline was in the original file.
259
# When you need a literal { or } or , in the value part of an alias you have to
260
# escape them by means of a backslash (\), this can lead to conflicts with the
261
# commands \{ and \} for these it is advised to use the version @{ and @} or use
262
# a double escape (\\{ and \\})
240
263
241
ALIASES                = "rst=\verbatim embed:rst:leading-asterisk" \
264
ALIASES                = "rst=\verbatim embed:rst:leading-asterisk" \
242
                         "endrst=\endverbatim"
265
                         "endrst=\endverbatim"
243
266
244
# This tag can be used to specify a number of word-keyword mappings (TCL only).
245
# A mapping has the form "name=value". For example adding "class=itcl::class"
246
# will allow you to use the command class in the itcl::class meaning.
247
248
TCL_SUBST              =
249
250
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
267
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
251
# only. Doxygen will then generate output that is more tailored for C. For
268
# only. Doxygen will then generate output that is more tailored for C. For
252
# instance, some of the names that are used will be different. The list of all
269
# instance, some of the names that are used will be different. The list of all
Lines 275-291 Link Here
275
292
276
OPTIMIZE_OUTPUT_VHDL   = NO
293
OPTIMIZE_OUTPUT_VHDL   = NO
277
294
295
# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice
296
# sources only. Doxygen will then generate output that is more tailored for that
297
# language. For instance, namespaces will be presented as modules, types will be
298
# separated into more groups, etc.
299
# The default value is: NO.
300
301
OPTIMIZE_OUTPUT_SLICE  = NO
302
278
# Doxygen selects the parser to use depending on the extension of the files it
303
# Doxygen selects the parser to use depending on the extension of the files it
279
# parses. With this tag you can assign which parser to use for a given
304
# parses. With this tag you can assign which parser to use for a given
280
# extension. Doxygen has a built-in mapping, but you can override or extend it
305
# extension. Doxygen has a built-in mapping, but you can override or extend it
281
# using this tag. The format is ext=language, where ext is a file extension, and
306
# using this tag. The format is ext=language, where ext is a file extension, and
282
# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
307
# language is one of the parsers supported by doxygen: IDL, Java, JavaScript,
283
# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
308
# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL,
284
# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
309
# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
285
# Fortran. In the later case the parser tries to guess whether the code is fixed
310
# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
286
# or free formatted code, this is the default for Fortran type files), VHDL. For
311
# tries to guess whether the code is fixed or free formatted code, this is the
287
# instance to make doxygen treat .inc files as Fortran files (default is PHP),
312
# default for Fortran type files). For instance to make doxygen treat .inc files
288
# and .f files as C (default is Fortran), use: inc=Fortran f=C.
313
# as Fortran files (default is PHP), and .f files as C (default is Fortran),
314
# use: inc=Fortran f=C.
289
#
315
#
290
# Note: For files without extension you can use no_extension as a placeholder.
316
# Note: For files without extension you can use no_extension as a placeholder.
291
#
317
#
Lines 296-302 Link Here
296
322
297
# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
323
# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
298
# according to the Markdown format, which allows for more readable
324
# according to the Markdown format, which allows for more readable
299
# documentation. See http://daringfireball.net/projects/markdown/ for details.
325
# documentation. See https://daringfireball.net/projects/markdown/ for details.
300
# The output of markdown processing is further processed by doxygen, so you can
326
# The output of markdown processing is further processed by doxygen, so you can
301
# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
327
# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
302
# case of backward compatibilities issues.
328
# case of backward compatibilities issues.
Lines 308-314 Link Here
308
# to that level are automatically included in the table of contents, even if
334
# to that level are automatically included in the table of contents, even if
309
# they do not have an id attribute.
335
# they do not have an id attribute.
310
# Note: This feature currently applies only to Markdown headings.
336
# Note: This feature currently applies only to Markdown headings.
311
# Minimum value: 0, maximum value: 99, default value: 0.
337
# Minimum value: 0, maximum value: 99, default value: 5.
312
# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
338
# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
313
339
314
TOC_INCLUDE_HEADINGS   = 0
340
TOC_INCLUDE_HEADINGS   = 0
Lines 338-344 Link Here
338
CPP_CLI_SUPPORT        = NO
364
CPP_CLI_SUPPORT        = NO
339
365
340
# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
366
# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
341
# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
367
# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen
342
# will parse them like normal C++ but will assume all classes use public instead
368
# will parse them like normal C++ but will assume all classes use public instead
343
# of private inheritance when no explicit protection keyword is present.
369
# of private inheritance when no explicit protection keyword is present.
344
# The default value is: NO.
370
# The default value is: NO.
Lines 444-449 Link Here
444
470
445
EXTRACT_PRIVATE        = NO
471
EXTRACT_PRIVATE        = NO
446
472
473
# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual
474
# methods of a class will be included in the documentation.
475
# The default value is: NO.
476
477
EXTRACT_PRIV_VIRTUAL   = NO
478
447
# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
479
# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
448
# scope will be included in the documentation.
480
# scope will be included in the documentation.
449
# The default value is: NO.
481
# The default value is: NO.
Lines 498-505 Link Here
498
HIDE_UNDOC_CLASSES     = NO
530
HIDE_UNDOC_CLASSES     = NO
499
531
500
# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
532
# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
501
# (class|struct|union) declarations. If set to NO, these declarations will be
533
# declarations. If set to NO, these declarations will be included in the
502
# included in the documentation.
534
# documentation.
503
# The default value is: NO.
535
# The default value is: NO.
504
536
505
HIDE_FRIEND_COMPOUNDS  = NO
537
HIDE_FRIEND_COMPOUNDS  = NO
Lines 522-528 Link Here
522
# names in lower-case letters. If set to YES, upper-case letters are also
554
# names in lower-case letters. If set to YES, upper-case letters are also
523
# allowed. This is useful if you have classes or files whose names only differ
555
# allowed. This is useful if you have classes or files whose names only differ
524
# in case and if your file system supports case sensitive file names. Windows
556
# in case and if your file system supports case sensitive file names. Windows
525
# and Mac users are advised to set this option to NO.
557
# (including Cygwin) ands Mac users are advised to set this option to NO.
526
# The default value is: system dependent.
558
# The default value is: system dependent.
527
559
528
CASE_SENSE_NAMES       = YES
560
CASE_SENSE_NAMES       = YES
Lines 709-715 Link Here
709
# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
741
# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
710
# the reference definitions. This must be a list of .bib files. The .bib
742
# the reference definitions. This must be a list of .bib files. The .bib
711
# extension is automatically appended if omitted. This requires the bibtex tool
743
# extension is automatically appended if omitted. This requires the bibtex tool
712
# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
744
# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
713
# For LaTeX the style of the bibliography can be controlled using
745
# For LaTeX the style of the bibliography can be controlled using
714
# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
746
# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
715
# search path. See also \cite for info how to create references.
747
# search path. See also \cite for info how to create references.
Lines 754-760 Link Here
754
# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
786
# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
755
# are documented, but have no documentation for their parameters or return
787
# are documented, but have no documentation for their parameters or return
756
# value. If set to NO, doxygen will only warn about wrong or incomplete
788
# value. If set to NO, doxygen will only warn about wrong or incomplete
757
# parameter documentation, but not about the absence of documentation.
789
# parameter documentation, but not about the absence of documentation. If
790
# EXTRACT_ALL is set to YES then this flag will automatically be disabled.
758
# The default value is: NO.
791
# The default value is: NO.
759
792
760
WARN_NO_PARAMDOC       = NO
793
WARN_NO_PARAMDOC       = NO
Lines 796-802 Link Here
796
# This tag can be used to specify the character encoding of the source files
829
# This tag can be used to specify the character encoding of the source files
797
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
830
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
798
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
831
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
799
# documentation (see: http://www.gnu.org/software/libiconv) for the list of
832
# documentation (see: https://www.gnu.org/software/libiconv/) for the list of
800
# possible encodings.
833
# possible encodings.
801
# The default value is: UTF-8.
834
# The default value is: UTF-8.
802
835
Lines 813-820 Link Here
813
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
846
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
814
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
847
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
815
# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
848
# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
816
# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
849
# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment),
817
# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.
850
# *.doc (to be provided as doxygen C comment), *.txt (to be provided as doxygen
851
# C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd,
852
# *.vhdl, *.ucf, *.qsf and *.ice.
818
853
819
FILE_PATTERNS          = *.c \
854
FILE_PATTERNS          = *.c \
820
                         *.cc \
855
                         *.cc \
Lines 1012-1018 Link Here
1012
STRIP_CODE_COMMENTS    = YES
1047
STRIP_CODE_COMMENTS    = YES
1013
1048
1014
# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
1049
# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
1015
# function all documented functions referencing it will be listed.
1050
# entity all documented functions referencing it will be listed.
1016
# The default value is: NO.
1051
# The default value is: NO.
1017
1052
1018
REFERENCED_BY_RELATION = NO
1053
REFERENCED_BY_RELATION = NO
Lines 1044-1055 Link Here
1044
# If the USE_HTAGS tag is set to YES then the references to source code will
1079
# If the USE_HTAGS tag is set to YES then the references to source code will
1045
# point to the HTML generated by the htags(1) tool instead of doxygen built-in
1080
# point to the HTML generated by the htags(1) tool instead of doxygen built-in
1046
# source browser. The htags tool is part of GNU's global source tagging system
1081
# source browser. The htags tool is part of GNU's global source tagging system
1047
# (see http://www.gnu.org/software/global/global.html). You will need version
1082
# (see https://www.gnu.org/software/global/global.html). You will need version
1048
# 4.8.6 or higher.
1083
# 4.8.6 or higher.
1049
#
1084
#
1050
# To use it do the following:
1085
# To use it do the following:
1051
# - Install the latest version of global
1086
# - Install the latest version of global
1052
# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
1087
# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file
1053
# - Make sure the INPUT points to the root of the source tree
1088
# - Make sure the INPUT points to the root of the source tree
1054
# - Run doxygen as normal
1089
# - Run doxygen as normal
1055
#
1090
#
Lines 1189-1195 Link Here
1189
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
1224
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
1190
# will adjust the colors in the style sheet and background images according to
1225
# will adjust the colors in the style sheet and background images according to
1191
# this color. Hue is specified as an angle on a colorwheel, see
1226
# this color. Hue is specified as an angle on a colorwheel, see
1192
# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
1227
# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
1193
# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
1228
# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
1194
# purple, and 360 is red again.
1229
# purple, and 360 is red again.
1195
# Minimum value: 0, maximum value: 359, default value: 220.
1230
# Minimum value: 0, maximum value: 359, default value: 220.
Lines 1225-1230 Link Here
1225
1260
1226
HTML_TIMESTAMP         = NO
1261
HTML_TIMESTAMP         = NO
1227
1262
1263
# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
1264
# documentation will contain a main index with vertical navigation menus that
1265
# are dynamically created via JavaScript. If disabled, the navigation index will
1266
# consists of multiple levels of tabs that are statically embedded in every HTML
1267
# page. Disable this option to support browsers that do not have JavaScript,
1268
# like the Qt help browser.
1269
# The default value is: YES.
1270
# This tag requires that the tag GENERATE_HTML is set to YES.
1271
1272
HTML_DYNAMIC_MENUS     = YES
1273
1228
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
1274
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
1229
# documentation will contain sections that can be hidden and shown after the
1275
# documentation will contain sections that can be hidden and shown after the
1230
# page has loaded.
1276
# page has loaded.
Lines 1248-1260 Link Here
1248
1294
1249
# If the GENERATE_DOCSET tag is set to YES, additional index files will be
1295
# If the GENERATE_DOCSET tag is set to YES, additional index files will be
1250
# generated that can be used as input for Apple's Xcode 3 integrated development
1296
# generated that can be used as input for Apple's Xcode 3 integrated development
1251
# environment (see: http://developer.apple.com/tools/xcode/), introduced with
1297
# environment (see: https://developer.apple.com/xcode/), introduced with OSX
1252
# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
1298
# 10.5 (Leopard). To create a documentation set, doxygen will generate a
1253
# Makefile in the HTML output directory. Running make will produce the docset in
1299
# Makefile in the HTML output directory. Running make will produce the docset in
1254
# that directory and running make install will install the docset in
1300
# that directory and running make install will install the docset in
1255
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
1301
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
1256
# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
1302
# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
1257
# for more information.
1303
# genXcode/_index.html for more information.
1258
# The default value is: NO.
1304
# The default value is: NO.
1259
# This tag requires that the tag GENERATE_HTML is set to YES.
1305
# This tag requires that the tag GENERATE_HTML is set to YES.
1260
1306
Lines 1293-1299 Link Here
1293
# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
1339
# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
1294
# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
1340
# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
1295
# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
1341
# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
1296
# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
1342
# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on
1297
# Windows.
1343
# Windows.
1298
#
1344
#
1299
# The HTML Help Workshop contains a compiler that can convert all HTML output
1345
# The HTML Help Workshop contains a compiler that can convert all HTML output
Lines 1369-1375 Link Here
1369
1415
1370
# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
1416
# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
1371
# Project output. For more information please see Qt Help Project / Namespace
1417
# Project output. For more information please see Qt Help Project / Namespace
1372
# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
1418
# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
1373
# The default value is: org.doxygen.Project.
1419
# The default value is: org.doxygen.Project.
1374
# This tag requires that the tag GENERATE_QHP is set to YES.
1420
# This tag requires that the tag GENERATE_QHP is set to YES.
1375
1421
Lines 1377-1383 Link Here
1377
1423
1378
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
1424
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
1379
# Help Project output. For more information please see Qt Help Project / Virtual
1425
# Help Project output. For more information please see Qt Help Project / Virtual
1380
# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
1426
# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-
1381
# folders).
1427
# folders).
1382
# The default value is: doc.
1428
# The default value is: doc.
1383
# This tag requires that the tag GENERATE_QHP is set to YES.
1429
# This tag requires that the tag GENERATE_QHP is set to YES.
Lines 1386-1392 Link Here
1386
1432
1387
# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
1433
# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
1388
# filter to add. For more information please see Qt Help Project / Custom
1434
# filter to add. For more information please see Qt Help Project / Custom
1389
# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
1435
# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
1390
# filters).
1436
# filters).
1391
# This tag requires that the tag GENERATE_QHP is set to YES.
1437
# This tag requires that the tag GENERATE_QHP is set to YES.
1392
1438
Lines 1394-1400 Link Here
1394
1440
1395
# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
1441
# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
1396
# custom filter to add. For more information please see Qt Help Project / Custom
1442
# custom filter to add. For more information please see Qt Help Project / Custom
1397
# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
1443
# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
1398
# filters).
1444
# filters).
1399
# This tag requires that the tag GENERATE_QHP is set to YES.
1445
# This tag requires that the tag GENERATE_QHP is set to YES.
1400
1446
Lines 1402-1408 Link Here
1402
1448
1403
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
1449
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
1404
# project's filter section matches. Qt Help Project / Filter Attributes (see:
1450
# project's filter section matches. Qt Help Project / Filter Attributes (see:
1405
# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
1451
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
1406
# This tag requires that the tag GENERATE_QHP is set to YES.
1452
# This tag requires that the tag GENERATE_QHP is set to YES.
1407
1453
1408
QHP_SECT_FILTER_ATTRS  =
1454
QHP_SECT_FILTER_ATTRS  =
Lines 1486-1491 Link Here
1486
1532
1487
EXT_LINKS_IN_WINDOW    = NO
1533
EXT_LINKS_IN_WINDOW    = NO
1488
1534
1535
# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg
1536
# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
1537
# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
1538
# the HTML output. These images will generally look nicer at scaled resolutions.
1539
# Possible values are: png The default and svg Looks nicer but requires the
1540
# pdf2svg tool.
1541
# The default value is: png.
1542
# This tag requires that the tag GENERATE_HTML is set to YES.
1543
1544
HTML_FORMULA_FORMAT    = png
1545
1489
# Use this tag to change the font size of LaTeX formulas included as images in
1546
# Use this tag to change the font size of LaTeX formulas included as images in
1490
# the HTML documentation. When you change the font size after a successful
1547
# the HTML documentation. When you change the font size after a successful
1491
# doxygen run you need to manually remove any form_*.png images from the HTML
1548
# doxygen run you need to manually remove any form_*.png images from the HTML
Lines 1495-1501 Link Here
1495
1552
1496
FORMULA_FONTSIZE       = 10
1553
FORMULA_FONTSIZE       = 10
1497
1554
1498
# Use the FORMULA_TRANPARENT tag to determine whether or not the images
1555
# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
1499
# generated for formulas are transparent PNGs. Transparent PNGs are not
1556
# generated for formulas are transparent PNGs. Transparent PNGs are not
1500
# supported properly for IE 6.0, but are supported on all modern browsers.
1557
# supported properly for IE 6.0, but are supported on all modern browsers.
1501
#
1558
#
Lines 1506-1513 Link Here
1506
1563
1507
FORMULA_TRANSPARENT    = YES
1564
FORMULA_TRANSPARENT    = YES
1508
1565
1566
# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
1567
# to create new LaTeX commands to be used in formulas as building blocks. See
1568
# the section "Including formulas" for details.
1569
1570
FORMULA_MACROFILE      =
1571
1509
# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
1572
# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
1510
# http://www.mathjax.org) which uses client side Javascript for the rendering
1573
# https://www.mathjax.org) which uses client side JavaScript for the rendering
1511
# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
1574
# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
1512
# installed or if you want to formulas look prettier in the HTML output. When
1575
# installed or if you want to formulas look prettier in the HTML output. When
1513
# enabled you may also need to install MathJax separately and configure the path
1576
# enabled you may also need to install MathJax separately and configure the path
Lines 1534-1541 Link Here
1534
# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
1597
# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
1535
# Content Delivery Network so you can quickly see the result without installing
1598
# Content Delivery Network so you can quickly see the result without installing
1536
# MathJax. However, it is strongly recommended to install a local copy of
1599
# MathJax. However, it is strongly recommended to install a local copy of
1537
# MathJax from http://www.mathjax.org before deployment.
1600
# MathJax from https://www.mathjax.org before deployment.
1538
# The default value is: http://cdn.mathjax.org/mathjax/latest.
1601
# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2.
1539
# This tag requires that the tag USE_MATHJAX is set to YES.
1602
# This tag requires that the tag USE_MATHJAX is set to YES.
1540
1603
1541
MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
1604
MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
Lines 1577-1583 Link Here
1577
SEARCHENGINE           = YES
1640
SEARCHENGINE           = YES
1578
1641
1579
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
1642
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
1580
# implemented using a web server instead of a web client using Javascript. There
1643
# implemented using a web server instead of a web client using JavaScript. There
1581
# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
1644
# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
1582
# setting. When disabled, doxygen will generate a PHP script for searching and
1645
# setting. When disabled, doxygen will generate a PHP script for searching and
1583
# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
1646
# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
Lines 1596-1602 Link Here
1596
#
1659
#
1597
# Doxygen ships with an example indexer (doxyindexer) and search engine
1660
# Doxygen ships with an example indexer (doxyindexer) and search engine
1598
# (doxysearch.cgi) which are based on the open source search engine library
1661
# (doxysearch.cgi) which are based on the open source search engine library
1599
# Xapian (see: http://xapian.org/).
1662
# Xapian (see: https://xapian.org/).
1600
#
1663
#
1601
# See the section "External Indexing and Searching" for details.
1664
# See the section "External Indexing and Searching" for details.
1602
# The default value is: NO.
1665
# The default value is: NO.
Lines 1609-1615 Link Here
1609
#
1672
#
1610
# Doxygen ships with an example indexer (doxyindexer) and search engine
1673
# Doxygen ships with an example indexer (doxyindexer) and search engine
1611
# (doxysearch.cgi) which are based on the open source search engine library
1674
# (doxysearch.cgi) which are based on the open source search engine library
1612
# Xapian (see: http://xapian.org/). See the section "External Indexing and
1675
# Xapian (see: https://xapian.org/). See the section "External Indexing and
1613
# Searching" for details.
1676
# Searching" for details.
1614
# This tag requires that the tag SEARCHENGINE is set to YES.
1677
# This tag requires that the tag SEARCHENGINE is set to YES.
1615
1678
Lines 1661-1681 Link Here
1661
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
1724
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
1662
# invoked.
1725
# invoked.
1663
#
1726
#
1664
# Note that when enabling USE_PDFLATEX this option is only used for generating
1727
# Note that when not enabling USE_PDFLATEX the default is latex when enabling
1665
# bitmaps for formulas in the HTML output, but not in the Makefile that is
1728
# USE_PDFLATEX the default is pdflatex and when in the later case latex is
1666
# written to the output directory.
1729
# chosen this is overwritten by pdflatex. For specific output languages the
1667
# The default file is: latex.
1730
# default can have been set differently, this depends on the implementation of
1731
# the output language.
1668
# This tag requires that the tag GENERATE_LATEX is set to YES.
1732
# This tag requires that the tag GENERATE_LATEX is set to YES.
1669
1733
1670
LATEX_CMD_NAME         = latex
1734
LATEX_CMD_NAME         = latex
1671
1735
1672
# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
1736
# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
1673
# index for LaTeX.
1737
# index for LaTeX.
1738
# Note: This tag is used in the Makefile / make.bat.
1739
# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file
1740
# (.tex).
1674
# The default file is: makeindex.
1741
# The default file is: makeindex.
1675
# This tag requires that the tag GENERATE_LATEX is set to YES.
1742
# This tag requires that the tag GENERATE_LATEX is set to YES.
1676
1743
1677
MAKEINDEX_CMD_NAME     = makeindex
1744
MAKEINDEX_CMD_NAME     = makeindex
1678
1745
1746
# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
1747
# generate index for LaTeX. In case there is no backslash (\) as first character
1748
# it will be automatically added in the LaTeX code.
1749
# Note: This tag is used in the generated output file (.tex).
1750
# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.
1751
# The default value is: makeindex.
1752
# This tag requires that the tag GENERATE_LATEX is set to YES.
1753
1754
LATEX_MAKEINDEX_CMD    = makeindex
1755
1679
# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
1756
# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
1680
# documents. This may be useful for small projects and may help to save some
1757
# documents. This may be useful for small projects and may help to save some
1681
# trees in general.
1758
# trees in general.
Lines 1796-1802 Link Here
1796
1873
1797
# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
1874
# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
1798
# bibliography, e.g. plainnat, or ieeetr. See
1875
# bibliography, e.g. plainnat, or ieeetr. See
1799
# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
1876
# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
1800
# The default value is: plain.
1877
# The default value is: plain.
1801
# This tag requires that the tag GENERATE_LATEX is set to YES.
1878
# This tag requires that the tag GENERATE_LATEX is set to YES.
1802
1879
Lines 1810-1815 Link Here
1810
1887
1811
LATEX_TIMESTAMP        = NO
1888
LATEX_TIMESTAMP        = NO
1812
1889
1890
# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
1891
# path from which the emoji images will be read. If a relative path is entered,
1892
# it will be relative to the LATEX_OUTPUT directory. If left blank the
1893
# LATEX_OUTPUT directory will be used.
1894
# This tag requires that the tag GENERATE_LATEX is set to YES.
1895
1896
LATEX_EMOJI_DIRECTORY  =
1897
1813
#---------------------------------------------------------------------------
1898
#---------------------------------------------------------------------------
1814
# Configuration options related to the RTF output
1899
# Configuration options related to the RTF output
1815
#---------------------------------------------------------------------------
1900
#---------------------------------------------------------------------------
Lines 1849-1857 Link Here
1849
1934
1850
RTF_HYPERLINKS         = NO
1935
RTF_HYPERLINKS         = NO
1851
1936
1852
# Load stylesheet definitions from file. Syntax is similar to doxygen's config
1937
# Load stylesheet definitions from file. Syntax is similar to doxygen's
1853
# file, i.e. a series of assignments. You only have to provide replacements,
1938
# configuration file, i.e. a series of assignments. You only have to provide
1854
# missing definitions are set to their default value.
1939
# replacements, missing definitions are set to their default value.
1855
#
1940
#
1856
# See also section "Doxygen usage" for information on how to generate the
1941
# See also section "Doxygen usage" for information on how to generate the
1857
# default style sheet that doxygen normally uses.
1942
# default style sheet that doxygen normally uses.
Lines 1860-1867 Link Here
1860
RTF_STYLESHEET_FILE    =
1945
RTF_STYLESHEET_FILE    =
1861
1946
1862
# Set optional variables used in the generation of an RTF document. Syntax is
1947
# Set optional variables used in the generation of an RTF document. Syntax is
1863
# similar to doxygen's config file. A template extensions file can be generated
1948
# similar to doxygen's configuration file. A template extensions file can be
1864
# using doxygen -e rtf extensionFile.
1949
# generated using doxygen -e rtf extensionFile.
1865
# This tag requires that the tag GENERATE_RTF is set to YES.
1950
# This tag requires that the tag GENERATE_RTF is set to YES.
1866
1951
1867
RTF_EXTENSIONS_FILE    =
1952
RTF_EXTENSIONS_FILE    =
Lines 1947-1952 Link Here
1947
2032
1948
XML_PROGRAMLISTING     = YES
2033
XML_PROGRAMLISTING     = YES
1949
2034
2035
# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include
2036
# namespace members in file scope as well, matching the HTML output.
2037
# The default value is: NO.
2038
# This tag requires that the tag GENERATE_XML is set to YES.
2039
2040
XML_NS_MEMB_FILE_SCOPE = NO
2041
1950
#---------------------------------------------------------------------------
2042
#---------------------------------------------------------------------------
1951
# Configuration options related to the DOCBOOK output
2043
# Configuration options related to the DOCBOOK output
1952
#---------------------------------------------------------------------------
2044
#---------------------------------------------------------------------------
Lines 1979-1987 Link Here
1979
#---------------------------------------------------------------------------
2071
#---------------------------------------------------------------------------
1980
2072
1981
# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
2073
# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
1982
# AutoGen Definitions (see http://autogen.sf.net) file that captures the
2074
# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
1983
# structure of the code including all documentation. Note that this feature is
2075
# the structure of the code including all documentation. Note that this feature
1984
# still experimental and incomplete at the moment.
2076
# is still experimental and incomplete at the moment.
1985
# The default value is: NO.
2077
# The default value is: NO.
1986
2078
1987
GENERATE_AUTOGEN_DEF   = NO
2079
GENERATE_AUTOGEN_DEF   = NO
Lines 2148-2159 Link Here
2148
2240
2149
EXTERNAL_PAGES         = YES
2241
EXTERNAL_PAGES         = YES
2150
2242
2151
# The PERL_PATH should be the absolute path and name of the perl script
2152
# interpreter (i.e. the result of 'which perl').
2153
# The default file (with absolute path) is: /usr/bin/perl.
2154
2155
PERL_PATH              = /usr/bin/perl
2156
2157
#---------------------------------------------------------------------------
2243
#---------------------------------------------------------------------------
2158
# Configuration options related to the dot tool
2244
# Configuration options related to the dot tool
2159
#---------------------------------------------------------------------------
2245
#---------------------------------------------------------------------------
Lines 2166-2180 Link Here
2166
# The default value is: YES.
2252
# The default value is: YES.
2167
2253
2168
CLASS_DIAGRAMS         = YES
2254
CLASS_DIAGRAMS         = YES
2169
2170
# You can define message sequence charts within doxygen comments using the \msc
2171
# command. Doxygen will then run the mscgen tool (see:
2172
# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
2173
# documentation. The MSCGEN_PATH tag allows you to specify the directory where
2174
# the mscgen tool resides. If left empty the tool is assumed to be found in the
2175
# default search path.
2176
2177
MSCGEN_PATH            =
2178
2255
2179
# You can include diagrams made with dia in doxygen documentation. Doxygen will
2256
# You can include diagrams made with dia in doxygen documentation. Doxygen will
2180
# then run dia to produce the diagram and insert it in the documentation. The
2257
# then run dia to produce the diagram and insert it in the documentation. The
(-)vis-0.6/doc/conf.py (-4 / +7 lines)
Lines 59-65 Link Here
59
59
60
# General information about the project.
60
# General information about the project.
61
project = 'Vis Editor'
61
project = 'Vis Editor'
62
copyright = '2017, Marc André Tanner'
62
copyright = '2014-2020 Marc André Tanner, et al.'
63
author = 'Marc André Tanner'
63
author = 'Marc André Tanner'
64
64
65
# The version info for the project you're documenting, acts as replacement for
65
# The version info for the project you're documenting, acts as replacement for
Lines 67-75 Link Here
67
# built documents.
67
# built documents.
68
#
68
#
69
# The short X.Y version.
69
# The short X.Y version.
70
version = '0.6'
70
version = '0.8'
71
# The full version, including alpha/beta/rc tags.
71
# The full version, including alpha/beta/rc tags.
72
release = '0.6'
72
release = '0.8'
73
73
74
# The language for content autogenerated by Sphinx. Refer to documentation
74
# The language for content autogenerated by Sphinx. Refer to documentation
75
# for a list of supported languages.
75
# for a list of supported languages.
Lines 86-95 Link Here
86
# The name of the Pygments (syntax highlighting) style to use.
86
# The name of the Pygments (syntax highlighting) style to use.
87
pygments_style = 'sphinx'
87
pygments_style = 'sphinx'
88
88
89
primary_domain = 'c'
90
highlight_language = 'c'
91
89
# If true, `todo` and `todoList` produce output, else they produce nothing.
92
# If true, `todo` and `todoList` produce output, else they produce nothing.
90
todo_include_todos = False
93
todo_include_todos = False
91
94
92
default_role = "any"
95
default_role = "c"
93
96
94
# -- Options for HTML output ----------------------------------------------
97
# -- Options for HTML output ----------------------------------------------
95
98
(-)vis-0.6/doc/text.rst (-3 / +3 lines)
Lines 4-10 Link Here
4
The core text management data structure which supports efficient
4
The core text management data structure which supports efficient
5
modifications and provides a byte string interface. Text positions
5
modifications and provides a byte string interface. Text positions
6
are represented as ``size_t``.  Valid addresses are in range ``[0,
6
are represented as ``size_t``.  Valid addresses are in range ``[0,
7
text_size(txt)]``. An invalid position is denoted by `EPOS`. Access to
7
text_size(txt)]``. An invalid position is denoted by ``EPOS``. Access to
8
the non-contigiuos pieces is available by means of an iterator interface
8
the non-contigiuos pieces is available by means of an iterator interface
9
or a copy mechanism. Text revisions are tracked in an history graph.
9
or a copy mechanism. Text revisions are tracked in an history graph.
10
10
Lines 77-83 Link Here
77
.. note:: The grapheme cluster boundaries are currently not implemented
77
.. note:: The grapheme cluster boundaries are currently not implemented
78
          according to `UAX#29 rules <http://unicode.org/reports/tr29>`_.
78
          according to `UAX#29 rules <http://unicode.org/reports/tr29>`_.
79
          Instead a base character followed by arbitrarily many combining
79
          Instead a base character followed by arbitrarily many combining
80
          character as reported by `wcwidth(3)` are skipped.
80
          character as reported by ``wcwidth(3)`` are skipped.
81
81
82
.. doxygengroup:: iterator_char
82
.. doxygengroup:: iterator_char
83
   :content-only:
83
   :content-only:
Lines 105-111 Link Here
105
all marks placed after the modification point. Reverting to an older text
105
all marks placed after the modification point. Reverting to an older text
106
state will hide all affected marks, redoing the changes will restore them.
106
state will hide all affected marks, redoing the changes will restore them.
107
107
108
.. warning:: Due to an optimization cached modifications (i.e. no `text_snaphot`
108
.. warning:: Due to an optimization cached modifications (i.e. no ``text_snaphot``
109
             was performed between setting the mark and issuing the changes) might
109
             was performed between setting the mark and issuing the changes) might
110
             not adjust mark positions accurately.
110
             not adjust mark positions accurately.
111
111
(-)vis-0.6/lua/lexers/bash.lua (-3 / +11 lines)
Lines 18-27 Link Here
18
local dq_str = l.delimited_range('"')
18
local dq_str = l.delimited_range('"')
19
local ex_str = l.delimited_range('`')
19
local ex_str = l.delimited_range('`')
20
local heredoc = '<<' * P(function(input, index)
20
local heredoc = '<<' * P(function(input, index)
21
  local s, e, _, delimiter =
21
  local s, e, minus, _, delimiter =
22
    input:find('%-?(["\']?)([%a_][%w_]*)%1[\n\r\f;]+', index)
22
    input:find('(-?)(["\']?)([%a_][%w_]*)%2[\n\r\f;]+', index)
23
  if s == index and delimiter then
23
  if s == index and delimiter then
24
    local _, e = input:find('[\n\r\f]+'..delimiter..'\n', e)
24
    -- If the starting delimiter of a here-doc begins with "-", then
25
    -- spaces are allowed to come before the closing delimiter.
26
    local close_pattern
27
    if minus == '-' then
28
      close_pattern = '[\n\r\f%s]+'..delimiter..'\n'
29
    else
30
      close_pattern = '[\n\r\f]+'..delimiter..'\n'
31
    end
32
    local _, e = input:find(close_pattern, e)
25
    return e and e + 1 or #input + 1
33
    return e and e + 1 or #input + 1
26
  end
34
  end
27
end)
35
end)
(-)vis-0.6/lua/lexers/git-rebase.lua (-1 / +2 lines)
Lines 1-4 Link Here
1
-- Copyright 2017 Marc André Tanner
1
-- Copyright 2017-2021 Marc André Tanner
2
-- git-rebase(1) LPeg lexer.
2
-- git-rebase(1) LPeg lexer.
3
3
4
local l = require('lexer')
4
local l = require('lexer')
Lines 22-27 Link Here
22
  'f', 'fixup',
22
  'f', 'fixup',
23
  'x', 'exec',
23
  'x', 'exec',
24
  'd', 'drop',
24
  'd', 'drop',
25
  'b', 'break',
25
  'l', 'label',
26
  'l', 'label',
26
  't', 'reset',
27
  't', 'reset',
27
  'm', 'merge',
28
  'm', 'merge',
(-)vis-0.6/lua/lexers/strace.lua (-6 / +8 lines)
Lines 1-9 Link Here
1
-- Copyright 2017 Marc André Tanner. See LICENSE.
1
-- Copyright 2017-2021 Marc André Tanner. See LICENSE.
2
-- strace(1) output lexer
2
-- strace(1) output lexer
3
3
4
local l = require('lexer')
4
local l = require('lexer')
5
local token, word_match = l.token, l.word_match
5
local token, word_match = l.token, l.word_match
6
local S = lpeg.S
6
local S, B = lpeg.S, lpeg.B
7
7
8
local M = {_NAME = 'strace'}
8
local M = {_NAME = 'strace'}
9
9
Lines 13-28 Link Here
13
local constant = token(l.CONSTANT, (l.upper + '_') * (l.upper + l.digit + '_')^0)
13
local constant = token(l.CONSTANT, (l.upper + '_') * (l.upper + l.digit + '_')^0)
14
local syscall = token(l.KEYWORD, l.starts_line(l.word))
14
local syscall = token(l.KEYWORD, l.starts_line(l.word))
15
local operator = token(l.OPERATOR, S('+-/*%<>~!=^&|?~:;,.()[]{}'))
15
local operator = token(l.OPERATOR, S('+-/*%<>~!=^&|?~:;,.()[]{}'))
16
local comment = token(l.COMMENT, l.nested_pair('/*', '*/') + ('(' * (l.alpha + ' ')^1 * ')\n'))
16
local comment = token(l.COMMENT, l.nested_pair('/*', '*/') + (l.delimited_range('()') * l.newline))
17
local result = token(l.TYPE, '= ' * l.integer)
17
local result = token(l.TYPE, B(' = ') * l.integer)
18
local identifier = token(l.IDENTIFIER, l.word)
18
19
19
M._rules = {
20
M._rules = {
20
  {'whitespace', ws},
21
  {'whitespace', ws},
21
  {'keyword', syscall},
22
  {'syscall', syscall},
22
  {'constant', constant},
23
  {'constant', constant},
23
  {'string', string},
24
  {'string', string},
24
  {'comment', comment},
25
  {'comment', comment},
25
  {'type', result},
26
  {'result', result},
27
  {'identifier', identifier},
26
  {'number', number},
28
  {'number', number},
27
  {'operator', operator},
29
  {'operator', operator},
28
}
30
}
(-)vis-0.6/lua/plugins/complete-filename.lua (-1 / +1 lines)
Lines 13-19 Link Here
13
	local prefix = file:content(range)
13
	local prefix = file:content(range)
14
	if not prefix then return end
14
	if not prefix then return end
15
	-- Strip leading delimiters for some languages
15
	-- Strip leading delimiters for some languages
16
	i, j = string.find(prefix, "[[(<'\"]+")
16
	local _, j = string.find(prefix, "[[(<'\"]+")
17
	if j then prefix = prefix:sub(j + 1) end
17
	if j then prefix = prefix:sub(j + 1) end
18
	local cmd = string.format("vis-complete --file '%s'", prefix:gsub("'", "'\\''"))
18
	local cmd = string.format("vis-complete --file '%s'", prefix:gsub("'", "'\\''"))
19
	local status, out, err = vis:pipe(file, { start = 0, finish = 0 }, cmd)
19
	local status, out, err = vis:pipe(file, { start = 0, finish = 0 }, cmd)
(-)vis-0.6/lua/plugins/filetype.lua (-9 / +30 lines)
Lines 40-46 Link Here
40
		ext = { "%.awk$" },
40
		ext = { "%.awk$" },
41
	},
41
	},
42
	bash = {
42
	bash = {
43
		ext = { "%.bash$", "%.csh$", "%.sh$", "%.zsh$" },
43
		ext = { "%.bash$", "%.csh$", "%.sh$", "%.zsh$" ,"^APKBUILD$", "%.ebuild$"},
44
		mime = { "text/x-shellscript", "application/x-shellscript" },
44
		mime = { "text/x-shellscript", "application/x-shellscript" },
45
	},
45
	},
46
	batch = {
46
	batch = {
Lines 149-154 Link Here
149
	gap = {
149
	gap = {
150
		ext = { "%.g$", "%.gd$", "%.gi$", "%.gap$" },
150
		ext = { "%.g$", "%.gd$", "%.gi$", "%.gap$" },
151
	},
151
	},
152
	gemini = {
153
		ext = { "%.gmi" },
154
		mime = { "text/gemini" },
155
	},
152
	gettext = {
156
	gettext = {
153
		ext = { "%.po$", "%.pot$" },
157
		ext = { "%.po$", "%.pot$" },
154
	},
158
	},
Lines 172-178 Link Here
172
		ext = { "%.go$" },
176
		ext = { "%.go$" },
173
	},
177
	},
174
	groovy = {
178
	groovy = {
175
		ext = { "%.groovy$", "%.gvy$" },
179
		ext = { "%.groovy$", "%.gvy$", "^Jenkinsfile$" },
176
	},
180
	},
177
	gtkrc = {
181
	gtkrc = {
178
		ext = { "%.gtkrc$" },
182
		ext = { "%.gtkrc$" },
Lines 204-210 Link Here
204
		ext = { "%.bsh$", "%.java$" },
208
		ext = { "%.bsh$", "%.java$" },
205
	},
209
	},
206
	javascript = {
210
	javascript = {
207
		ext = { "%.js$", "%.jsfl$" },
211
		ext = { "%.cjs$", "%.js$", "%.jsfl$", "%.mjs$", "%.ts$" },
208
	},
212
	},
209
	json = {
213
	json = {
210
		ext = { "%.json$" },
214
		ext = { "%.json$" },
Lines 227-233 Link Here
227
		ext = { "%.less$" },
231
		ext = { "%.less$" },
228
	},
232
	},
229
	lilypond = {
233
	lilypond = {
230
		ext = { "%.lily$", "%.ly$" },
234
		ext = { "%.ily$", "%.ly$" },
231
	},
235
	},
232
	lisp = {
236
	lisp = {
233
		ext = { "%.cl$", "%.el$", "%.lisp$", "%.lsp$" },
237
		ext = { "%.cl$", "%.el$", "%.lisp$", "%.lsp$" },
Lines 246-251 Link Here
246
	makefile = {
250
	makefile = {
247
		ext = { "%.iface$", "%.mak$", "%.mk$", "GNUmakefile", "makefile", "Makefile" },
251
		ext = { "%.iface$", "%.mak$", "%.mk$", "GNUmakefile", "makefile", "Makefile" },
248
		mime = { "text/x-makefile" },
252
		mime = { "text/x-makefile" },
253
		detect = function(_, data)
254
			return data:match("^#!/usr/bin/make")
255
		end
249
	},
256
	},
250
	man = {
257
	man = {
251
		ext = {
258
		ext = {
Lines 258-263 Link Here
258
		ext = { "%.md$", "%.markdown$" },
265
		ext = { "%.md$", "%.markdown$" },
259
		mime = { "text/x-markdown" },
266
		mime = { "text/x-markdown" },
260
	},
267
	},
268
	meson = {
269
		ext = { "^meson%.build$" },
270
	},
261
	moonscript = {
271
	moonscript = {
262
		ext = { "%.moon$" },
272
		ext = { "%.moon$" },
263
		mime = { "text/x-moon" },
273
		mime = { "text/x-moon" },
Lines 343-348 Link Here
343
	rhtml = {
353
	rhtml = {
344
		ext = { "%.erb$", "%.rhtml$" },
354
		ext = { "%.erb$", "%.rhtml$" },
345
	},
355
	},
356
	routeros = {
357
		ext = { "%.rsc" },
358
		detect = function(_, data)
359
			return data:match("^#.* by RouterOS")
360
		end
361
	},
346
	rstats = {
362
	rstats = {
347
		ext = { "%.R$", "%.Rout$", "%.Rhistory$", "%.Rt$", "Rout.save", "Rout.fail" },
363
		ext = { "%.R$", "%.Rout$", "%.Rhistory$", "%.Rt$", "Rout.save", "Rout.fail" },
348
	},
364
	},
Lines 363-369 Link Here
363
		mime = { "text/x-scala" },
379
		mime = { "text/x-scala" },
364
	},
380
	},
365
	scheme = {
381
	scheme = {
366
		ext = { "%.sch$", "%.scm$", "%.sld$", "%.sls$", "%.ss$" },
382
		ext = { "%.rkt$", "%.sch$", "%.scm$", "%.sld$", "%.sls$", "%.ss$" },
367
	},
383
	},
368
	smalltalk = {
384
	smalltalk = {
369
		ext = { "%.changes$", "%.st$", "%.sources$" },
385
		ext = { "%.changes$", "%.st$", "%.sources$" },
Lines 381-387 Link Here
381
		ext = { "%.ddl$", "%.sql$" },
397
		ext = { "%.ddl$", "%.sql$" },
382
	},
398
	},
383
	strace = {
399
	strace = {
384
		detect = function(file, data)
400
		detect = function(_, data)
385
			return data:match("^execve%(")
401
			return data:match("^execve%(")
386
		end
402
		end
387
	},
403
	},
Lines 403-409 Link Here
403
	},
419
	},
404
	text = {
420
	text = {
405
		ext = { "%.txt$" },
421
		ext = { "%.txt$" },
406
		mime = { "text/plain" },
422
		-- Do *not* list mime "text/plain" here, it is covered below,
423
		-- see 'try text lexer as a last resort'
407
	},
424
	},
408
	toml = {
425
	toml = {
409
		ext = { "%.toml$" },
426
		ext = { "%.toml$" },
Lines 422-428 Link Here
422
		ext = { "%.vcf$", "%.vcard$" },
439
		ext = { "%.vcf$", "%.vcard$" },
423
	},
440
	},
424
	verilog = {
441
	verilog = {
425
		ext = { "%.v$", "%.ver$" },
442
		ext = { "%.v$", "%.ver$", "%.sv$" },
426
	},
443
	},
427
	vhdl = {
444
	vhdl = {
428
		ext = { "%.vh$", "%.vhd$", "%.vhdl$" },
445
		ext = { "%.vh$", "%.vhd$", "%.vhdl$" },
Lines 443-448 Link Here
443
		ext = { "%.yaml$", "%.yml$" },
460
		ext = { "%.yaml$", "%.yml$" },
444
		mime = { "text/x-yaml" },
461
		mime = { "text/x-yaml" },
445
	},
462
	},
463
	zig = {
464
		ext = { "%.zig$" },
465
	},
446
}
466
}
447
467
448
vis.events.subscribe(vis.events.WIN_OPEN, function(win)
468
vis.events.subscribe(vis.events.WIN_OPEN, function(win)
Lines 484-493 Link Here
484
	end
504
	end
485
505
486
	-- run file(1) to determine mime type
506
	-- run file(1) to determine mime type
507
	local mime
487
	if name ~= nil then
508
	if name ~= nil then
488
		local file = io.popen(string.format("file -bL --mime-type -- '%s'", name:gsub("'", "'\\''")))
509
		local file = io.popen(string.format("file -bL --mime-type -- '%s'", name:gsub("'", "'\\''")))
489
		if file then
510
		if file then
490
			local mime = file:read('*all')
511
			mime = file:read('*all')
491
			file:close()
512
			file:close()
492
			if mime then
513
			if mime then
493
				mime = mime:gsub('%s*$', '')
514
				mime = mime:gsub('%s*$', '')
(-)vis-0.6/lua/vis.lua (-1 / +3 lines)
Lines 103-109 Link Here
103
-- Checks whether a subsequent @{require} call will succeed.
103
-- Checks whether a subsequent @{require} call will succeed.
104
-- @tparam string name the module name to check
104
-- @tparam string name the module name to check
105
-- @treturn bool whether the module was found
105
-- @treturn bool whether the module was found
106
vis.module_exist = function(vis, name)
106
vis.module_exist = function(_, name)
107
	for _, searcher in ipairs(package.searchers or package.loaders) do
107
	for _, searcher in ipairs(package.searchers or package.loaders) do
108
		local loader = searcher(name)
108
		local loader = searcher(name)
109
		if type(loader) == 'function' then
109
		if type(loader) == 'function' then
Lines 151-156 Link Here
151
	WIN_HIGHLIGHT = "Event::WIN_HIGHLIGHT", -- see @{win_highlight}
151
	WIN_HIGHLIGHT = "Event::WIN_HIGHLIGHT", -- see @{win_highlight}
152
	WIN_OPEN = "Event::WIN_OPEN", -- see @{win_open}
152
	WIN_OPEN = "Event::WIN_OPEN", -- see @{win_open}
153
	WIN_STATUS = "Event::WIN_STATUS", -- see @{win_status}
153
	WIN_STATUS = "Event::WIN_STATUS", -- see @{win_status}
154
	TERM_CSI = "Event::TERM_CSI", -- see @{term_csi}
154
}
155
}
155
156
156
events.file_close = function(...) events.emit(events.FILE_CLOSE, ...) end
157
events.file_close = function(...) events.emit(events.FILE_CLOSE, ...) end
Lines 165-170 Link Here
165
events.win_highlight = function(...) events.emit(events.WIN_HIGHLIGHT, ...) end
166
events.win_highlight = function(...) events.emit(events.WIN_HIGHLIGHT, ...) end
166
events.win_open = function(...) events.emit(events.WIN_OPEN, ...) end
167
events.win_open = function(...) events.emit(events.WIN_OPEN, ...) end
167
events.win_status = function(...) events.emit(events.WIN_STATUS, ...) end
168
events.win_status = function(...) events.emit(events.WIN_STATUS, ...) end
169
events.term_csi = function(...) events.emit(events.TERM_CSI, ...) end
168
170
169
local handlers = {}
171
local handlers = {}
170
172
(-)vis-0.6/main.c (-203 / +72 lines)
Lines 66-73 Link Here
66
static const char *selections_remove_column_except(Vis*, const char *keys, const Arg *arg);
66
static const char *selections_remove_column_except(Vis*, const char *keys, const Arg *arg);
67
/* move to the previous (arg->i < 0) or next (arg->i > 0) selection */
67
/* move to the previous (arg->i < 0) or next (arg->i > 0) selection */
68
static const char *selections_navigate(Vis*, const char *keys, const Arg *arg);
68
static const char *selections_navigate(Vis*, const char *keys, const Arg *arg);
69
/* select the word the selection is currently over */
70
static const char *selections_match_word(Vis*, const char *keys, const Arg *arg);
71
/* select the next region matching the current selection */
69
/* select the next region matching the current selection */
72
static const char *selections_match_next(Vis*, const char *keys, const Arg *arg);
70
static const char *selections_match_next(Vis*, const char *keys, const Arg *arg);
73
/* clear current selection but select next match */
71
/* clear current selection but select next match */
Lines 88-101 Link Here
88
static const char *selections_complement(Vis*, const char *keys, const Arg *arg);
86
static const char *selections_complement(Vis*, const char *keys, const Arg *arg);
89
/* subtract selections from mark */
87
/* subtract selections from mark */
90
static const char *selections_minus(Vis*, const char *keys, const Arg *arg);
88
static const char *selections_minus(Vis*, const char *keys, const Arg *arg);
91
/* pairwise combine selections from mark */
92
static const char *selections_combine(Vis*, const char *keys, const Arg *arg);
93
static Filerange combine_union(const Filerange*, const Filerange*);
94
static Filerange combine_intersect(const Filerange*, const Filerange*);
95
static Filerange combine_longer(const Filerange*, const Filerange*);
96
static Filerange combine_shorter(const Filerange*, const Filerange*);
97
static Filerange combine_leftmost(const Filerange*, const Filerange*);
98
static Filerange combine_rightmost(const Filerange*, const Filerange*);
99
/* adjust current used count according to keys */
89
/* adjust current used count according to keys */
100
static const char *count(Vis*, const char *keys, const Arg *arg);
90
static const char *count(Vis*, const char *keys, const Arg *arg);
101
/* move to the count-th line or if not given either to the first (arg->i < 0)
91
/* move to the count-th line or if not given either to the first (arg->i < 0)
Lines 104-110 Link Here
104
/* make the current action use the operator indicated by arg->i */
94
/* make the current action use the operator indicated by arg->i */
105
static const char *operator(Vis*, const char *keys, const Arg *arg);
95
static const char *operator(Vis*, const char *keys, const Arg *arg);
106
/* blocks to read a key and performs movement indicated by arg->i which
96
/* blocks to read a key and performs movement indicated by arg->i which
107
 * should be one of VIS_MOVE_{RIGHT,LEFT}_{TO,TILL} */
97
 * should be one of VIS_MOVE_{TO,TILL}_{,LINE}_{RIGHT,LEFT}*/
108
static const char *movement_key(Vis*, const char *keys, const Arg *arg);
98
static const char *movement_key(Vis*, const char *keys, const Arg *arg);
109
/* perform the movement as indicated by arg->i */
99
/* perform the movement as indicated by arg->i */
110
static const char *movement(Vis*, const char *keys, const Arg *arg);
100
static const char *movement(Vis*, const char *keys, const Arg *arg);
Lines 232-239 Link Here
232
	VIS_ACTION_PROMPT_SEARCH_BACKWARD,
222
	VIS_ACTION_PROMPT_SEARCH_BACKWARD,
233
	VIS_ACTION_TILL_LEFT,
223
	VIS_ACTION_TILL_LEFT,
234
	VIS_ACTION_TILL_RIGHT,
224
	VIS_ACTION_TILL_RIGHT,
225
	VIS_ACTION_TILL_LINE_LEFT,
226
	VIS_ACTION_TILL_LINE_RIGHT,
235
	VIS_ACTION_TO_LEFT,
227
	VIS_ACTION_TO_LEFT,
236
	VIS_ACTION_TO_RIGHT,
228
	VIS_ACTION_TO_RIGHT,
229
	VIS_ACTION_TO_LINE_LEFT,
230
	VIS_ACTION_TO_LINE_RIGHT,
237
	VIS_ACTION_REGISTER,
231
	VIS_ACTION_REGISTER,
238
	VIS_ACTION_OPERATOR_CHANGE,
232
	VIS_ACTION_OPERATOR_CHANGE,
239
	VIS_ACTION_OPERATOR_DELETE,
233
	VIS_ACTION_OPERATOR_DELETE,
Lines 264-276 Link Here
264
	VIS_ACTION_WINDOW_SLIDE_DOWN,
258
	VIS_ACTION_WINDOW_SLIDE_DOWN,
265
	VIS_ACTION_PUT_AFTER,
259
	VIS_ACTION_PUT_AFTER,
266
	VIS_ACTION_PUT_BEFORE,
260
	VIS_ACTION_PUT_BEFORE,
267
	VIS_ACTION_SELECTIONS_MATCH_WORD,
268
	VIS_ACTION_SELECTIONS_NEW_LINE_ABOVE,
261
	VIS_ACTION_SELECTIONS_NEW_LINE_ABOVE,
269
	VIS_ACTION_SELECTIONS_NEW_LINE_ABOVE_FIRST,
262
	VIS_ACTION_SELECTIONS_NEW_LINE_ABOVE_FIRST,
270
	VIS_ACTION_SELECTIONS_NEW_LINE_BELOW,
263
	VIS_ACTION_SELECTIONS_NEW_LINE_BELOW,
271
	VIS_ACTION_SELECTIONS_NEW_LINE_BELOW_LAST,
264
	VIS_ACTION_SELECTIONS_NEW_LINE_BELOW_LAST,
272
	VIS_ACTION_SELECTIONS_NEW_LINES_BEGIN,
265
	VIS_ACTION_SELECTIONS_NEW_LINES_BEGIN,
273
	VIS_ACTION_SELECTIONS_NEW_LINES_END,
266
	VIS_ACTION_SELECTIONS_NEW_LINES_END,
267
	VIS_ACTION_SELECTIONS_NEW_MATCH_ALL,
274
	VIS_ACTION_SELECTIONS_NEW_MATCH_NEXT,
268
	VIS_ACTION_SELECTIONS_NEW_MATCH_NEXT,
275
	VIS_ACTION_SELECTIONS_NEW_MATCH_SKIP,
269
	VIS_ACTION_SELECTIONS_NEW_MATCH_SKIP,
276
	VIS_ACTION_SELECTIONS_ALIGN,
270
	VIS_ACTION_SELECTIONS_ALIGN,
Lines 291-302 Link Here
291
	VIS_ACTION_SELECTIONS_INTERSECT,
285
	VIS_ACTION_SELECTIONS_INTERSECT,
292
	VIS_ACTION_SELECTIONS_COMPLEMENT,
286
	VIS_ACTION_SELECTIONS_COMPLEMENT,
293
	VIS_ACTION_SELECTIONS_MINUS,
287
	VIS_ACTION_SELECTIONS_MINUS,
294
	VIS_ACTION_SELECTIONS_COMBINE_UNION,
295
	VIS_ACTION_SELECTIONS_COMBINE_INTERSECT,
296
	VIS_ACTION_SELECTIONS_COMBINE_LONGER,
297
	VIS_ACTION_SELECTIONS_COMBINE_SHORTER,
298
	VIS_ACTION_SELECTIONS_COMBINE_LEFTMOST,
299
	VIS_ACTION_SELECTIONS_COMBINE_RIGHTMOST,
300
	VIS_ACTION_TEXT_OBJECT_WORD_OUTER,
288
	VIS_ACTION_TEXT_OBJECT_WORD_OUTER,
301
	VIS_ACTION_TEXT_OBJECT_WORD_INNER,
289
	VIS_ACTION_TEXT_OBJECT_WORD_INNER,
302
	VIS_ACTION_TEXT_OBJECT_LONGWORD_OUTER,
290
	VIS_ACTION_TEXT_OBJECT_LONGWORD_OUTER,
Lines 318-325 Link Here
318
	VIS_ACTION_TEXT_OBJECT_SINGLE_QUOTE_INNER,
306
	VIS_ACTION_TEXT_OBJECT_SINGLE_QUOTE_INNER,
319
	VIS_ACTION_TEXT_OBJECT_BACKTICK_OUTER,
307
	VIS_ACTION_TEXT_OBJECT_BACKTICK_OUTER,
320
	VIS_ACTION_TEXT_OBJECT_BACKTICK_INNER,
308
	VIS_ACTION_TEXT_OBJECT_BACKTICK_INNER,
321
	VIS_ACTION_TEXT_OBJECT_ENTIRE_OUTER,
322
	VIS_ACTION_TEXT_OBJECT_ENTIRE_INNER,
323
	VIS_ACTION_TEXT_OBJECT_LINE_OUTER,
309
	VIS_ACTION_TEXT_OBJECT_LINE_OUTER,
324
	VIS_ACTION_TEXT_OBJECT_LINE_INNER,
310
	VIS_ACTION_TEXT_OBJECT_LINE_INNER,
325
	VIS_ACTION_TEXT_OBJECT_INDENTATION,
311
	VIS_ACTION_TEXT_OBJECT_INDENTATION,
Lines 739-761 Link Here
739
	[VIS_ACTION_TILL_LEFT] = {
725
	[VIS_ACTION_TILL_LEFT] = {
740
		"vis-motion-till-left",
726
		"vis-motion-till-left",
741
		VIS_HELP("Till after the occurrence of character to the left")
727
		VIS_HELP("Till after the occurrence of character to the left")
742
		movement_key, { .i = VIS_MOVE_LEFT_TILL }
728
		movement_key, { .i = VIS_MOVE_TILL_LEFT }
743
	},
729
	},
744
	[VIS_ACTION_TILL_RIGHT] = {
730
	[VIS_ACTION_TILL_RIGHT] = {
745
		"vis-motion-till-right",
731
		"vis-motion-till-right",
746
		VIS_HELP("Till before the occurrence of character to the right")
732
		VIS_HELP("Till before the occurrence of character to the right")
747
		movement_key, { .i = VIS_MOVE_RIGHT_TILL }
733
		movement_key, { .i = VIS_MOVE_TILL_RIGHT }
748
	},
734
	},
735
	[VIS_ACTION_TILL_LINE_LEFT] = {
736
		"vis-motion-till-line-left",
737
		VIS_HELP("Till after the occurrence of character to the left on the current line")
738
		movement_key, { .i = VIS_MOVE_TILL_LINE_LEFT }
739
	},
740
	[VIS_ACTION_TILL_LINE_RIGHT] = {
741
		"vis-motion-till-line-right",
742
		VIS_HELP("Till before the occurrence of character to the right on the current line")
743
		movement_key, { .i = VIS_MOVE_TILL_LINE_RIGHT }
744
	},
749
	[VIS_ACTION_TO_LEFT] = {
745
	[VIS_ACTION_TO_LEFT] = {
750
		"vis-motion-to-left",
746
		"vis-motion-to-left",
751
		VIS_HELP("To the first occurrence of character to the left")
747
		VIS_HELP("To the first occurrence of character to the left")
752
		movement_key, { .i = VIS_MOVE_LEFT_TO }
748
		movement_key, { .i = VIS_MOVE_TO_LEFT }
753
	},
749
	},
754
	[VIS_ACTION_TO_RIGHT] = {
750
	[VIS_ACTION_TO_RIGHT] = {
755
		"vis-motion-to-right",
751
		"vis-motion-to-right",
756
		VIS_HELP("To the first occurrence of character to the right")
752
		VIS_HELP("To the first occurrence of character to the right")
757
		movement_key, { .i = VIS_MOVE_RIGHT_TO }
753
		movement_key, { .i = VIS_MOVE_TO_RIGHT }
758
	},
754
	},
755
	[VIS_ACTION_TO_LINE_LEFT] = {
756
		"vis-motion-to-line-left",
757
		VIS_HELP("To the first occurrence of character to the left on the current line")
758
		movement_key, { .i = VIS_MOVE_TO_LINE_LEFT }
759
	},
760
	[VIS_ACTION_TO_LINE_RIGHT] = {
761
		"vis-motion-to-line-right",
762
		VIS_HELP("To the first occurrence of character to the right on the current line")
763
		movement_key, { .i = VIS_MOVE_TO_LINE_RIGHT }
764
	},
759
	[VIS_ACTION_REGISTER] = {
765
	[VIS_ACTION_REGISTER] = {
760
		"vis-register",
766
		"vis-register",
761
		VIS_HELP("Use given register for next operator")
767
		VIS_HELP("Use given register for next operator")
Lines 906-916 Link Here
906
		VIS_HELP("Put text before the cursor")
912
		VIS_HELP("Put text before the cursor")
907
		operator, { .i = VIS_OP_PUT_BEFORE }
913
		operator, { .i = VIS_OP_PUT_BEFORE }
908
	},
914
	},
909
	[VIS_ACTION_SELECTIONS_MATCH_WORD] = {
910
		"vis-selections-select-word",
911
		VIS_HELP("Select word under cursor")
912
		selections_match_word,
913
	},
914
	[VIS_ACTION_SELECTIONS_NEW_LINE_ABOVE] = {
915
	[VIS_ACTION_SELECTIONS_NEW_LINE_ABOVE] = {
915
		"vis-selection-new-lines-above",
916
		"vis-selection-new-lines-above",
916
		VIS_HELP("Create a new selection on the line above")
917
		VIS_HELP("Create a new selection on the line above")
Lines 941-946 Link Here
941
		VIS_HELP("Create a new selection at the end of every line covered by selection")
942
		VIS_HELP("Create a new selection at the end of every line covered by selection")
942
		operator, { .i = VIS_OP_CURSOR_EOL }
943
		operator, { .i = VIS_OP_CURSOR_EOL }
943
	},
944
	},
945
	[VIS_ACTION_SELECTIONS_NEW_MATCH_ALL] = {
946
		"vis-selection-new-match-all",
947
		VIS_HELP("Select all regions matching the current selection")
948
		selections_match_next, { .b = true }
949
	},
944
	[VIS_ACTION_SELECTIONS_NEW_MATCH_NEXT] = {
950
	[VIS_ACTION_SELECTIONS_NEW_MATCH_NEXT] = {
945
		"vis-selection-new-match-next",
951
		"vis-selection-new-match-next",
946
		VIS_HELP("Select the next region matching the current selection")
952
		VIS_HELP("Select the next region matching the current selection")
Lines 1041-1076 Link Here
1041
		VIS_HELP("Subtract selections from mark")
1047
		VIS_HELP("Subtract selections from mark")
1042
		selections_minus
1048
		selections_minus
1043
	},
1049
	},
1044
	[VIS_ACTION_SELECTIONS_COMBINE_UNION] = {
1045
		"vis-selections-combine-union",
1046
		VIS_HELP("Pairwise union with selections from mark")
1047
		selections_combine, { .combine = combine_union }
1048
	},
1049
	[VIS_ACTION_SELECTIONS_COMBINE_INTERSECT] = {
1050
		"vis-selections-combine-intersect",
1051
		VIS_HELP("Pairwise intersect with selections from mark")
1052
		selections_combine, { .combine = combine_intersect }
1053
	},
1054
	[VIS_ACTION_SELECTIONS_COMBINE_LONGER] = {
1055
		"vis-selections-combine-longer",
1056
		VIS_HELP("Pairwise combine: take longer")
1057
		selections_combine, { .combine = combine_longer }
1058
	},
1059
	[VIS_ACTION_SELECTIONS_COMBINE_SHORTER] = {
1060
		"vis-selections-combine-shorter",
1061
		VIS_HELP("Pairwise combine: take shorter")
1062
		selections_combine, { .combine = combine_shorter }
1063
	},
1064
	[VIS_ACTION_SELECTIONS_COMBINE_LEFTMOST] = {
1065
		"vis-selections-combine-leftmost",
1066
		VIS_HELP("Pairwise combine: leftmost")
1067
		selections_combine, { .combine = combine_leftmost }
1068
	},
1069
	[VIS_ACTION_SELECTIONS_COMBINE_RIGHTMOST] = {
1070
		"vis-selections-combine-rightmost",
1071
		VIS_HELP("Pairwise combine: rightmost")
1072
		selections_combine, { .combine = combine_rightmost }
1073
	},
1074
	[VIS_ACTION_TEXT_OBJECT_WORD_OUTER] = {
1050
	[VIS_ACTION_TEXT_OBJECT_WORD_OUTER] = {
1075
		"vis-textobject-word-outer",
1051
		"vis-textobject-word-outer",
1076
		VIS_HELP("A word leading and trailing whitespace included")
1052
		VIS_HELP("A word leading and trailing whitespace included")
Lines 1176-1191 Link Here
1176
		VIS_HELP("A backtick delimited string (inner variant)")
1152
		VIS_HELP("A backtick delimited string (inner variant)")
1177
		textobj, { .i = VIS_TEXTOBJECT_INNER_BACKTICK }
1153
		textobj, { .i = VIS_TEXTOBJECT_INNER_BACKTICK }
1178
	},
1154
	},
1179
	[VIS_ACTION_TEXT_OBJECT_ENTIRE_OUTER] = {
1180
		"vis-textobject-entire-outer",
1181
		VIS_HELP("The whole text content")
1182
		textobj, { .i = VIS_TEXTOBJECT_OUTER_ENTIRE }
1183
	},
1184
	[VIS_ACTION_TEXT_OBJECT_ENTIRE_INNER] = {
1185
		"vis-textobject-entire-inner",
1186
		VIS_HELP("The whole text content, except for leading and trailing empty lines")
1187
		textobj, { .i = VIS_TEXTOBJECT_INNER_ENTIRE }
1188
	},
1189
	[VIS_ACTION_TEXT_OBJECT_LINE_OUTER] = {
1155
	[VIS_ACTION_TEXT_OBJECT_LINE_OUTER] = {
1190
		"vis-textobject-line-outer",
1156
		"vis-textobject-line-outer",
1191
		VIS_HELP("The whole line")
1157
		VIS_HELP("The whole line")
Lines 1389-1407 Link Here
1389
	return keys;
1355
	return keys;
1390
}
1356
}
1391
1357
1392
static const char *selections_match_word(Vis *vis, const char *keys, const Arg *arg) {
1358
static Selection *selection_new(View *view, Filerange *r, bool isprimary) {
1393
	Text *txt = vis_text(vis);
1394
	View *view = vis_view(vis);
1395
	for (Selection *s = view_selections(view); s; s = view_selections_next(s)) {
1396
		Filerange word = text_object_word(txt, view_cursors_pos(s));
1397
		if (text_range_valid(&word))
1398
			view_selections_set(s, &word);
1399
	}
1400
	vis_mode_switch(vis, VIS_MODE_VISUAL);
1401
	return keys;
1402
}
1403
1404
static const Selection *selection_new_primary(View *view, Filerange *r) {
1405
	Text *txt = view_text(view);
1359
	Text *txt = view_text(view);
1406
	size_t pos = text_char_prev(txt, r->end);
1360
	size_t pos = text_char_prev(txt, r->end);
1407
	Selection *s = view_selections_new(view, pos);
1361
	Selection *s = view_selections_new(view, pos);
Lines 1409-1449 Link Here
1409
		return NULL;
1363
		return NULL;
1410
	view_selections_set(s, r);
1364
	view_selections_set(s, r);
1411
	view_selections_anchor(s, true);
1365
	view_selections_anchor(s, true);
1412
	view_selections_primary_set(s);
1366
	if (isprimary)
1367
		view_selections_primary_set(s);
1413
	return s;
1368
	return s;
1414
}
1369
}
1415
1370
1416
static const char *selections_match_next_literal(Vis *vis, const char *keys, const Arg *arg) {
1417
	Text *txt = vis_text(vis);
1418
	View *view = vis_view(vis);
1419
	Selection *s = view_selections_primary_get(view);
1420
	Filerange sel = view_selections_get(s);
1421
	size_t len = text_range_size(&sel);
1422
	if (!len)
1423
		return keys;
1424
1425
	char *buf = text_bytes_alloc0(txt, sel.start, len);
1426
	if (!buf)
1427
		return keys;
1428
1429
	size_t start = text_find_next(txt, sel.end, buf);
1430
	Filerange match = text_range_new(start, start+len);
1431
	if (start != sel.end && selection_new_primary(view, &match))
1432
		goto out;
1433
1434
	sel = view_selections_get(view_selections(view));
1435
	start = text_find_prev(txt, sel.start, buf);
1436
	if (start == sel.start)
1437
		goto out;
1438
1439
	match = text_range_new(start, start+len);
1440
	selection_new_primary(view, &match);
1441
1442
out:
1443
	free(buf);
1444
	return keys;
1445
}
1446
1447
static const char *selections_match_next(Vis *vis, const char *keys, const Arg *arg) {
1371
static const char *selections_match_next(Vis *vis, const char *keys, const Arg *arg) {
1448
	Text *txt = vis_text(vis);
1372
	Text *txt = vis_text(vis);
1449
	View *view = vis_view(vis);
1373
	View *view = vis_view(vis);
Lines 1452-1475 Link Here
1452
	if (!text_range_valid(&sel))
1376
	if (!text_range_valid(&sel))
1453
		return keys;
1377
		return keys;
1454
1378
1455
	Filerange word = text_object_word(txt, view_cursors_pos(s));
1379
	static bool match_word;
1456
	if (!text_range_equal(&sel, &word))
1457
		return selections_match_next_literal(vis, keys, arg);
1458
1380
1381
	if (view_selections_count(view) == 1) {
1382
		Filerange word = text_object_word(txt, view_cursors_pos(s));
1383
		match_word = text_range_equal(&sel, &word);
1384
	}
1385
1386
	Filerange (*find_next)(Text *, size_t, const char *) = text_object_word_find_next;
1387
	Filerange (*find_prev)(Text *, size_t, const char *) = text_object_word_find_prev;
1388
	if (!match_word) {
1389
		find_next = text_object_find_next;
1390
		find_prev = text_object_find_prev;
1391
	}
1392
1459
	char *buf = text_bytes_alloc0(txt, sel.start, text_range_size(&sel));
1393
	char *buf = text_bytes_alloc0(txt, sel.start, text_range_size(&sel));
1460
	if (!buf)
1394
	if (!buf)
1461
		return keys;
1395
		return keys;
1462
1396
1463
	word = text_object_word_find_next(txt, sel.end, buf);
1397
	bool match_all = arg->b;
1464
	if (text_range_valid(&word) && selection_new_primary(view, &word))
1398
	Filerange primary = sel;
1465
		goto out;
1466
1399
1467
	sel = view_selections_get(view_selections(view));
1400
	for (;;) {
1468
	word = text_object_word_find_prev(txt, sel.start, buf);
1401
		sel = find_next(txt, sel.end, buf);
1469
	if (!text_range_valid(&word))
1402
		if (!text_range_valid(&sel))
1470
		goto out;
1403
			break;
1471
	selection_new_primary(view, &word);
1404
		if (selection_new(view, &sel, !match_all) && !match_all)
1405
			goto out;
1406
	}
1472
1407
1408
	sel = primary;
1409
1410
	for (;;) {
1411
		sel = find_prev(txt, sel.start, buf);
1412
		if (!text_range_valid(&sel))
1413
			break;
1414
		if (selection_new(view, &sel, !match_all) && !match_all)
1415
			break;
1416
	}
1417
1473
out:
1418
out:
1474
	free(buf);
1419
	free(buf);
1475
	return keys;
1420
	return keys;
Lines 1825-1907 Link Here
1825
	return keys;
1770
	return keys;
1826
}
1771
}
1827
1772
1828
static Filerange combine_union(const Filerange *r1, const Filerange *r2) {
1829
	if (!r1)
1830
		return *r2;
1831
	if (!r2)
1832
		return *r1;
1833
	return text_range_union(r1, r2);
1834
}
1835
1836
static Filerange combine_intersect(const Filerange *r1, const Filerange *r2) {
1837
	if (!r1 || !r2)
1838
		return text_range_empty();
1839
	return text_range_intersect(r1, r2);
1840
}
1841
1842
static Filerange combine_longer(const Filerange *r1, const Filerange *r2) {
1843
	if (!r1)
1844
		return *r2;
1845
	if (!r2)
1846
		return *r1;
1847
	size_t l1 = text_range_size(r1);
1848
	size_t l2 = text_range_size(r2);
1849
	return l1 < l2 ? *r2 : *r1;
1850
}
1851
1852
static Filerange combine_shorter(const Filerange *r1, const Filerange *r2) {
1853
	if (!r1)
1854
		return *r2;
1855
	if (!r2)
1856
		return *r1;
1857
	size_t l1 = text_range_size(r1);
1858
	size_t l2 = text_range_size(r2);
1859
	return l1 < l2 ? *r1 : *r2;
1860
}
1861
1862
static Filerange combine_leftmost(const Filerange *r1, const Filerange *r2) {
1863
	if (!r1)
1864
		return *r2;
1865
	if (!r2)
1866
		return *r1;
1867
	return r1->start < r2->start || (r1->start == r2->start && r1->end < r2->end) ? *r1 : *r2;
1868
}
1869
1870
static Filerange combine_rightmost(const Filerange *r1, const Filerange *r2) {
1871
	if (!r1)
1872
		return *r2;
1873
	if (!r2)
1874
		return *r1;
1875
	return r1->start < r2->start || (r1->start == r2->start && r1->end < r2->end) ? *r2 : *r1;
1876
}
1877
1878
static const char *selections_combine(Vis *vis, const char *keys, const Arg *arg) {
1879
	Win *win = vis_window(vis);
1880
	View *view = vis_view(vis);
1881
	enum VisMark mark = vis_mark_used(vis);
1882
	Array a = view_selections_get_all(view);
1883
	Array b = vis_mark_get(win, mark);
1884
	Array sel;
1885
	array_init_from(&sel, &a);
1886
1887
	Filerange *r1 = array_get(&a, 0), *r2 = array_get(&b, 0);
1888
	for (size_t i = 0, j = 0; r1 || r2; r1 = array_get(&a, ++i), r2 = array_get(&b, ++j)) {
1889
		Filerange new = arg->combine(r1, r2);
1890
		if (text_range_valid(&new))
1891
			array_add(&sel, &new);
1892
	}
1893
1894
	vis_mark_normalize(&sel);
1895
	selections_set(vis, view, &sel);
1896
	vis_cancel(vis);
1897
1898
	array_release(&a);
1899
	array_release(&b);
1900
	array_release(&sel);
1901
1902
	return keys;
1903
}
1904
1905
static const char *replace(Vis *vis, const char *keys, const Arg *arg) {
1773
static const char *replace(Vis *vis, const char *keys, const Arg *arg) {
1906
	if (!keys[0]) {
1774
	if (!keys[0]) {
1907
		vis_keymap_disable(vis);
1775
		vis_keymap_disable(vis);
Lines 2227-2233 Link Here
2227
			vis_motion(vis, VIS_MOVE_LINE_BEGIN);
2095
			vis_motion(vis, VIS_MOVE_LINE_BEGIN);
2228
			vis_keys_feed(vis, "<vis-motion-line-begin>");
2096
			vis_keys_feed(vis, "<vis-motion-line-begin>");
2229
		}
2097
		}
2230
		vis_keys_feed(vis, "<Enter><Up>");
2098
		vis_keys_feed(vis, "<Enter><vis-motion-line-up>");
2231
	}
2099
	}
2232
	return keys;
2100
	return keys;
2233
}
2101
}
Lines 2360-2365 Link Here
2360
		.win_close = vis_lua_win_close,
2228
		.win_close = vis_lua_win_close,
2361
		.win_highlight = vis_lua_win_highlight,
2229
		.win_highlight = vis_lua_win_highlight,
2362
		.win_status = vis_lua_win_status,
2230
		.win_status = vis_lua_win_status,
2231
		.term_csi = vis_lua_term_csi,
2363
	};
2232
	};
2364
2233
2365
	vis = vis_new(ui_term_new(), &event);
2234
	vis = vis_new(ui_term_new(), &event);
(-)vis-0.6/man/vis-clipboard.1 (+4 lines)
Lines 12-20 Link Here
12
.Pp
12
.Pp
13
.Nm vis-clipboard
13
.Nm vis-clipboard
14
.Fl -copy
14
.Fl -copy
15
.Op Fl -selection Ar selection
15
.Pp
16
.Pp
16
.Nm vis-clipboard
17
.Nm vis-clipboard
17
.Fl -paste
18
.Fl -paste
19
.Op Fl -selection Ar selection
18
.
20
.
19
.Sh DESCRIPTION
21
.Sh DESCRIPTION
20
.Nm vis-clipboard
22
.Nm vis-clipboard
Lines 50-55 Link Here
50
.Nm vis-clipboard
52
.Nm vis-clipboard
51
reads the content of the system clipboard,
53
reads the content of the system clipboard,
52
and writes it to standard output.
54
and writes it to standard output.
55
.It Fl -selection Ar selection
56
specify which selection to use, options are "primary" or "clipboard"
53
.El
57
.El
54
.
58
.
55
.Sh ENVIRONMENT
59
.Sh ENVIRONMENT
(-)vis-0.6/man/vis.1 (-33 / +29 lines)
Lines 123-129 Link Here
123
.Ss Marks
123
.Ss Marks
124
.
124
.
125
A mark associates a symbolic name to a set of selections.
125
A mark associates a symbolic name to a set of selections.
126
A stored selection becomes invalid when its delimiting boundaries changes
126
A stored selection becomes invalid when its delimiting boundaries change
127
in the underlying buffer.
127
in the underlying buffer.
128
If said changes are later undone the mark becomes valid again.
128
If said changes are later undone the mark becomes valid again.
129
.Ic m
129
.Ic m
Lines 769-784 Link Here
769
.
769
.
770
.Ss Operators
770
.Ss Operators
771
.
771
.
772
Operators perform a certain operation an a text range indicated by either a
772
Operators perform a certain operation on a text range indicated by either a
773
motion, a text object or an existing selection.
773
motion, a text object or an existing selection.
774
.Pp
774
.Pp
775
When used in normal mode, the following operators wait for a motion, putting
776
vis into operator pending mode.
775
.Bl -tag -width XXXXXXXXXX -compact
777
.Bl -tag -width XXXXXXXXXX -compact
776
.It Ic c
778
.It Ic c
777
change, delete range and enter insert mode
779
change, delete range and enter insert mode
778
.
780
.
779
.It Ic d
781
.It Ic d
780
delete range
782
delete, cut range to register
781
.
783
.
784
.It Ic <
785
shift-left, decrease indent
786
.
787
.It Ic >
788
shift-right, increase indent
789
.
790
.It Ic y
791
yank, copy range to register
792
.El
793
.Pp
794
When used in normal mode, the following actions take effect immediately.
795
.Bl -tag -width XXXXXXXXXX -compact
782
.It Ic =
796
.It Ic =
783
format, filter range through
797
format, filter range through
784
.Xr fmt 1
798
.Xr fmt 1
Lines 789-794 Link Here
789
.It Ic gU
803
.It Ic gU
790
make uppercase
804
make uppercase
791
.
805
.
806
.It Ic g~
807
swap case
808
.
792
.It Ic J
809
.It Ic J
793
join lines, insert spaces in between
810
join lines, insert spaces in between
794
.
811
.
Lines 796-814 Link Here
796
join lines remove any delimiting white spaces
813
join lines remove any delimiting white spaces
797
.
814
.
798
.It Ic p
815
.It Ic p
799
put, insert register content
816
put register content after cursor
800
.
817
.
801
.It Ic <
818
.It Ic P
802
shift-left, decrease indent
819
put register content before cursor
803
.
820
.
804
.It Ic >
805
shift-right, increase indent
806
.
807
.It Ic ~
808
swap case
809
.
810
.It Ic y
811
yank, copy range to register
812
.El
821
.El
813
.
822
.
814
.Ss Motions
823
.Ss Motions
Lines 1026-1037 Link Here
1026
.It Ic gN
1035
.It Ic gN
1027
matches the last used search term in backward direction
1036
matches the last used search term in backward direction
1028
.
1037
.
1029
.It Ic ae
1030
entire file content
1031
.
1032
.It Ic ie
1033
entire file content except for leading and trailing empty lines
1034
.
1035
.It Ic al
1038
.It Ic al
1036
current line
1039
current line
1037
.
1040
.
Lines 1103-1108 Link Here
1103
.It Aq Ic S-Tab
1106
.It Aq Ic S-Tab
1104
right align selections by inserting spaces
1107
right align selections by inserting spaces
1105
.
1108
.
1109
.It Aq Ic C-a
1110
create new selections everywhere matching current word or selection
1111
.
1106
.It Aq Ic C-n
1112
.It Aq Ic C-n
1107
create new selection and select next word matching current selection
1113
create new selection and select next word matching current selection
1108
.
1114
.
Lines 1160-1179 Link Here
1160
set intersection
1166
set intersection
1161
.It Ic \e
1167
.It Ic \e
1162
set minus
1168
set minus
1163
.It Ic \&!
1169
.It Ic ~
1164
set complement
1170
set complement
1165
.It Ic z\&|
1166
pairwise union
1167
.It Ic z&
1168
pairwise intersection
1169
.It Ic z+
1170
pairwise combine, choose longer
1171
.It Ic z-
1172
pairwise combine, choose shorter
1173
.It Ic z<
1174
pairwise combine, choose leftmost
1175
.It Ic z>
1176
pairwise combine, choose rightmost
1177
.El
1171
.El
1178
.
1172
.
1179
.Sh VI(M) COMMANDS
1173
.Sh VI(M) COMMANDS
Lines 1427-1432 Link Here
1427
WARNING: modifying a memory mapped file in-place will cause data loss.
1421
WARNING: modifying a memory mapped file in-place will cause data loss.
1428
.It Ic layout Op Do v Dc or Do h Dc
1422
.It Ic layout Op Do v Dc or Do h Dc
1429
Whether to use vertical or horizontal layout.
1423
Whether to use vertical or horizontal layout.
1424
.It Cm ignorecase , Cm ic Op Cm off
1425
Whether to ignore case when searching.
1430
.El
1426
.El
1431
.
1427
.
1432
.Sh COMMAND and SEARCH PROMPT
1428
.Sh COMMAND and SEARCH PROMPT
(-)vis-0.6/map.c (-13 lines)
Lines 78-96 Link Here
78
	return !map_empty(map_prefix(map, prefix));
78
	return !map_empty(map_prefix(map, prefix));
79
}
79
}
80
80
81
static bool leaf(const char *key, void *value, void *data)
82
{
83
	int *nodes = data;
84
	return (*nodes)++ < 1;
85
}
86
87
bool map_leaf(const Map *map, const char *prefix)
88
{
89
	int nodes = 0;
90
	map_iterate(map_prefix(map, prefix), leaf, &nodes);
91
	return nodes == 1;
92
}
93
94
bool map_put(Map *map, const char *k, const void *value)
81
bool map_put(Map *map, const char *k, const void *value)
95
{
82
{
96
	size_t len = strlen(k);
83
	size_t len = strlen(k);
(-)vis-0.6/map.h (-5 lines)
Lines 35-45 Link Here
35
 */
35
 */
36
bool map_contains(const Map*, const char *prefix);
36
bool map_contains(const Map*, const char *prefix);
37
/**
37
/**
38
 * Check whether the given prefix can be extended to exactly one map element.
39
 * True iff the prefix map contains exactly one element.
40
 */
41
bool map_leaf(const Map*, const char *prefix);
42
/**
43
 * Store a key value pair in the map.
38
 * Store a key value pair in the map.
44
 * @return False if we run out of memory (``errno = ENOMEM``), or if the key
39
 * @return False if we run out of memory (``errno = ENOMEM``), or if the key
45
 *         already appears in the map (``errno = EEXIST``).
40
 *         already appears in the map (``errno = EEXIST``).
(-)vis-0.6/sam.c (-16 / +25 lines)
Lines 2-8 Link Here
2
 * Heavily inspired (and partially based upon) the X11 version of
2
 * Heavily inspired (and partially based upon) the X11 version of
3
 * Rob Pike's sam text editor originally written for Plan 9.
3
 * Rob Pike's sam text editor originally written for Plan 9.
4
 *
4
 *
5
 *  Copyright © 2016-2018 Marc André Tanner <mat at brain-dump.org>
5
 *  Copyright © 2016-2020 Marc André Tanner <mat at brain-dump.org>
6
 *  Copyright © 1998 by Lucent Technologies
6
 *  Copyright © 1998 by Lucent Technologies
7
 *
7
 *
8
 * Permission to use, copy, modify, and distribute this software for any
8
 * Permission to use, copy, modify, and distribute this software for any
Lines 23-28 Link Here
23
#include <errno.h>
23
#include <errno.h>
24
#include <unistd.h>
24
#include <unistd.h>
25
#include <limits.h>
25
#include <limits.h>
26
#include <fcntl.h>
26
#include "sam.h"
27
#include "sam.h"
27
#include "vis-core.h"
28
#include "vis-core.h"
28
#include "buffer.h"
29
#include "buffer.h"
Lines 144-150 Link Here
144
145
145
static const CommandDef cmds[] = {
146
static const CommandDef cmds[] = {
146
	//      name            help
147
	//      name            help
147
	//      flags, default command, implemenation
148
	//      flags, default command, implementation
148
	{
149
	{
149
		"a",            VIS_HELP("Append text after range")
150
		"a",            VIS_HELP("Append text after range")
150
		CMD_TEXT, NULL, cmd_append
151
		CMD_TEXT, NULL, cmd_append
Lines 277-283 Link Here
277
	const char *names[3];            /* name and optional alias */
278
	const char *names[3];            /* name and optional alias */
278
	enum VisOption flags;            /* option type, etc. */
279
	enum VisOption flags;            /* option type, etc. */
279
	VIS_HELP_DECL(const char *help;) /* short, one line help text */
280
	VIS_HELP_DECL(const char *help;) /* short, one line help text */
280
	VisOptionFunction *func;         /* option handler, NULL for bulitins */
281
	VisOptionFunction *func;         /* option handler, NULL for builtins */
281
	void *context;                   /* context passed to option handler function */
282
	void *context;                   /* context passed to option handler function */
282
} OptionDef;
283
} OptionDef;
283
284
Lines 299-304 Link Here
299
	OPTION_LOAD_METHOD,
300
	OPTION_LOAD_METHOD,
300
	OPTION_CHANGE_256COLORS,
301
	OPTION_CHANGE_256COLORS,
301
	OPTION_LAYOUT,
302
	OPTION_LAYOUT,
303
	OPTION_IGNORECASE,
302
};
304
};
303
305
304
static const OptionDef options[] = {
306
static const OptionDef options[] = {
Lines 387-392 Link Here
387
		VIS_OPTION_TYPE_STRING,
389
		VIS_OPTION_TYPE_STRING,
388
		VIS_HELP("Vertical or horizontal window layout")
390
		VIS_HELP("Vertical or horizontal window layout")
389
	},
391
	},
392
	[OPTION_IGNORECASE] = {
393
		{ "ignorecase", "ic" },
394
		VIS_OPTION_TYPE_BOOL,
395
		VIS_HELP("Ignore case when searching")
396
	},
390
};
397
};
391
398
392
bool sam_init(Vis *vis) {
399
bool sam_init(Vis *vis) {
Lines 1005-1011 Link Here
1005
	size_t start = range->start, end = range->end, line;
1012
	size_t start = range->start, end = range->end, line;
1006
	if (sign > 0) {
1013
	if (sign > 0) {
1007
		char c;
1014
		char c;
1008
		if (start < end && end > 0 && text_byte_get(txt, end-1, &c) && c == '\n')
1015
		if (start < end && text_byte_get(txt, end-1, &c) && c == '\n')
1009
			end--;
1016
			end--;
1010
		line = text_lineno_by_pos(txt, end);
1017
		line = text_lineno_by_pos(txt, end);
1011
		line = text_pos_by_lineno(txt, line + offset);
1018
		line = text_pos_by_lineno(txt, line + offset);
Lines 1386-1399 Link Here
1386
	Text *txt = win->file->text;
1393
	Text *txt = win->file->text;
1387
1394
1388
	if (cmd->regex) {
1395
	if (cmd->regex) {
1389
		bool trailing_match = false;
1396
		size_t start = range->start, end = range->end;
1390
		size_t start = range->start, end = range->end, last_start = EPOS;
1397
		size_t last_start = argv[0][0] == 'x' ? EPOS : start;
1391
		size_t nsub = 1 + text_regex_nsub(cmd->regex);
1398
		size_t nsub = 1 + text_regex_nsub(cmd->regex);
1392
		if (nsub > MAX_REGEX_SUB)
1399
		if (nsub > MAX_REGEX_SUB)
1393
			nsub = MAX_REGEX_SUB;
1400
			nsub = MAX_REGEX_SUB;
1394
		RegexMatch match[MAX_REGEX_SUB];
1401
		RegexMatch match[MAX_REGEX_SUB];
1395
		while (start < end || trailing_match) {
1402
		while (start <= end) {
1396
			trailing_match = false;
1397
			char c;
1403
			char c;
1398
			int flags = start > range->start &&
1404
			int flags = start > range->start &&
1399
			            text_byte_get(txt, start - 1, &c) && c != '\n' ?
1405
			            text_byte_get(txt, start - 1, &c) && c != '\n' ?
Lines 1406-1412 Link Here
1406
				if (argv[0][0] == 'x')
1412
				if (argv[0][0] == 'x')
1407
					r = text_range_new(match[0].start, match[0].end);
1413
					r = text_range_new(match[0].start, match[0].end);
1408
				else
1414
				else
1409
					r = text_range_new(start, match[0].start);
1415
					r = text_range_new(last_start, match[0].start);
1410
				if (match[0].start == match[0].end) {
1416
				if (match[0].start == match[0].end) {
1411
					if (last_start == match[0].start) {
1417
					if (last_start == match[0].start) {
1412
						start++;
1418
						start++;
Lines 1417-1432 Link Here
1417
					 * matches the zero-length string immediately after a
1423
					 * matches the zero-length string immediately after a
1418
					 * newline. Try filtering out the last such match at EOF.
1424
					 * newline. Try filtering out the last such match at EOF.
1419
					 */
1425
					 */
1420
					if (end == match[0].start && start > range->start)
1426
					if (end == match[0].start && start > range->start &&
1427
					    text_byte_get(txt, end-1, &c) && c == '\n')
1421
						break;
1428
						break;
1429
					start = match[0].end + 1;
1430
				} else {
1431
					start = match[0].end;
1422
				}
1432
				}
1423
				start = match[0].end;
1424
				if (start == end)
1425
					trailing_match = true;
1426
			} else {
1433
			} else {
1427
				if (argv[0][0] == 'y')
1434
				if (argv[0][0] == 'y')
1428
					r = text_range_new(start, end);
1435
					r = text_range_new(start, end);
1429
				start = end;
1436
				start = end + 1;
1430
			}
1437
			}
1431
1438
1432
			if (text_range_valid(&r)) {
1439
			if (text_range_valid(&r)) {
Lines 1435-1446 Link Here
1435
						Register *reg = &vis->registers[VIS_REG_AMPERSAND+i];
1442
						Register *reg = &vis->registers[VIS_REG_AMPERSAND+i];
1436
						register_put_range(vis, reg, txt, &match[i]);
1443
						register_put_range(vis, reg, txt, &match[i]);
1437
					}
1444
					}
1445
					last_start = match[0].end;
1446
				} else {
1447
					last_start = start;
1438
				}
1448
				}
1439
				if (simulate)
1449
				if (simulate)
1440
					count++;
1450
					count++;
1441
				else
1451
				else
1442
					ret &= sam_execute(vis, win, cmd->cmd, NULL, &r);
1452
					ret &= sam_execute(vis, win, cmd->cmd, NULL, &r);
1443
				last_start = start;
1444
			}
1453
			}
1445
		}
1454
		}
1446
	} else {
1455
	} else {
Lines 1670-1676 Link Here
1670
		if (write_entire_file)
1679
		if (write_entire_file)
1671
			*r = text_range_new(0, text_size(text));
1680
			*r = text_range_new(0, text_size(text));
1672
1681
1673
		TextSave *ctx = text_save_begin(text, path, file->save_method);
1682
		TextSave *ctx = text_save_begin(text, AT_FDCWD, path, file->save_method);
1674
		if (!ctx) {
1683
		if (!ctx) {
1675
			const char *msg = errno ? strerror(errno) : "try changing `:set savemethod`";
1684
			const char *msg = errno ? strerror(errno) : "try changing `:set savemethod`";
1676
			vis_info_show(vis, "Can't write `%s': %s", path, msg);
1685
			vis_info_show(vis, "Can't write `%s': %s", path, msg);
(-)vis-0.6/text-motions.c (+2 lines)
Lines 287-292 Link Here
287
size_t text_line_down(Text *txt, size_t pos) {
287
size_t text_line_down(Text *txt, size_t pos) {
288
	int width = text_line_width_get(txt, pos);
288
	int width = text_line_width_get(txt, pos);
289
	size_t next = text_line_next(txt, pos);
289
	size_t next = text_line_next(txt, pos);
290
	if (next == text_size(txt))
291
		return pos;
290
	return text_line_width_set(txt, next, width);
292
	return text_line_width_set(txt, next, width);
291
}
293
}
292
294
(-)vis-0.6/text-motions.h (-7 / +7 lines)
Lines 1-8 Link Here
1
#ifndef TEXT_MOTIONS_H
1
#ifndef TEXT_MOTIONS_H
2
#define TEXT_MOTIONS_H
2
#define TEXT_MOTIONS_H
3
3
4
/* these function all take a position in bytes from the start of the file,
4
/* these functions all take a position in bytes from the start of the file,
5
 * perform a certain movement and return the new postion. if the movement
5
 * perform a certain movement and return the new postion. If the movement
6
 * is not possible the original position is returned unchanged. */
6
 * is not possible the original position is returned unchanged. */
7
7
8
#include <stddef.h>
8
#include <stddef.h>
Lines 20-26 Link Here
20
size_t text_codepoint_prev(Text*, size_t pos);
20
size_t text_codepoint_prev(Text*, size_t pos);
21
21
22
/* find the given substring either in forward or backward direction.
22
/* find the given substring either in forward or backward direction.
23
 * does not wrap around at file start / end. if no match is found return
23
 * does not wrap around at file start / end. If no match is found return
24
 * original position */
24
 * original position */
25
size_t text_find_next(Text*, size_t pos, const char *s);
25
size_t text_find_next(Text*, size_t pos, const char *s);
26
size_t text_find_prev(Text*, size_t pos, const char *s);
26
size_t text_find_prev(Text*, size_t pos, const char *s);
Lines 69-75 Link Here
69
/*
69
/*
70
 * A longword consists of a sequence of non-blank characters, separated with
70
 * A longword consists of a sequence of non-blank characters, separated with
71
 * white space. TODO?: An empty line is also considered to be a word.
71
 * white space. TODO?: An empty line is also considered to be a word.
72
 * This is equivalant to a WORD in vim terminology.
72
 * This is equivalent to a WORD in vim terminology.
73
 */
73
 */
74
size_t text_longword_end_next(Text*, size_t pos);
74
size_t text_longword_end_next(Text*, size_t pos);
75
size_t text_longword_end_prev(Text*, size_t pos);
75
size_t text_longword_end_prev(Text*, size_t pos);
Lines 79-85 Link Here
79
 * A word consists of a sequence of letters, digits and underscores, or a
79
 * A word consists of a sequence of letters, digits and underscores, or a
80
 * sequence of other non-blank characters, separated with white space.
80
 * sequence of other non-blank characters, separated with white space.
81
 * TODO?: An empty line is also considered to be a word.
81
 * TODO?: An empty line is also considered to be a word.
82
 * This is equivalant to a word (lowercase) in vim terminology.
82
 * This is equivalent to a word (lowercase) in vim terminology.
83
 */
83
 */
84
size_t text_word_end_next(Text*, size_t pos);
84
size_t text_word_end_next(Text*, size_t pos);
85
size_t text_word_end_prev(Text*, size_t pos);
85
size_t text_word_end_prev(Text*, size_t pos);
Lines 116-128 Link Here
116
size_t text_block_end(Text*, size_t pos);
116
size_t text_block_end(Text*, size_t pos);
117
size_t text_parenthesis_start(Text*, size_t pos);
117
size_t text_parenthesis_start(Text*, size_t pos);
118
size_t text_parenthesis_end(Text*, size_t pos);
118
size_t text_parenthesis_end(Text*, size_t pos);
119
/* search coresponding '(', ')', '{', '}', '[', ']', '>', '<', '"', ''' */
119
/* search corresponding '(', ')', '{', '}', '[', ']', '>', '<', '"', ''' */
120
size_t text_bracket_match(Text*, size_t pos, const Filerange *limits);
120
size_t text_bracket_match(Text*, size_t pos, const Filerange *limits);
121
/* same as above but explicitly specify symbols to match */
121
/* same as above but explicitly specify symbols to match */
122
size_t text_bracket_match_symbol(Text*, size_t pos, const char *symbols, const Filerange *limits);
122
size_t text_bracket_match_symbol(Text*, size_t pos, const char *symbols, const Filerange *limits);
123
123
124
/* search the given regex pattern in either forward or backward direction,
124
/* search the given regex pattern in either forward or backward direction,
125
 * starting from pos. does wrap around if no match was found. */
125
 * starting from pos. Does wrap around if no match was found. */
126
size_t text_search_forward(Text *txt, size_t pos, Regex *regex);
126
size_t text_search_forward(Text *txt, size_t pos, Regex *regex);
127
size_t text_search_backward(Text *txt, size_t pos, Regex *regex);
127
size_t text_search_backward(Text *txt, size_t pos, Regex *regex);
128
128
(-)vis-0.6/text-objects.c (-31 / +31 lines)
Lines 15-33 Link Here
15
	return text_range_new(0, text_size(txt));
15
	return text_range_new(0, text_size(txt));
16
}
16
}
17
17
18
Filerange text_object_entire_inner(Text *txt, size_t pos) {
19
	char c;
20
	Filerange r = text_object_entire(txt, pos);
21
	Iterator it = text_iterator_get(txt, r.start);
22
	if (text_iterator_byte_get(&it, &c) && c == '\n')
23
		while (text_iterator_byte_next(&it, &c) && c == '\n');
24
	r.start = it.pos;
25
	it = text_iterator_get(txt, r.end);
26
	while (text_iterator_char_prev(&it, &c) && c == '\n');
27
	r.end = it.pos;
28
	return text_range_linewise(txt, &r);
29
}
30
31
static Filerange text_object_customword(Text *txt, size_t pos, int (*isboundary)(int)) {
18
static Filerange text_object_customword(Text *txt, size_t pos, int (*isboundary)(int)) {
32
	Filerange r;
19
	Filerange r;
33
	char c, prev = '0', next = '0';
20
	char c, prev = '0', next = '0';
Lines 40-66 Link Here
40
	if (space(c)) {
27
	if (space(c)) {
41
		r.start = text_char_next(txt, text_customword_end_prev(txt, pos, isboundary));
28
		r.start = text_char_next(txt, text_customword_end_prev(txt, pos, isboundary));
42
		r.end = text_customword_start_next(txt, pos, isboundary);
29
		r.end = text_customword_start_next(txt, pos, isboundary);
43
	} else if (boundary(prev) && boundary(next)) {
30
	} else if (boundary(c)) {
44
		if (boundary(c)) {
31
		if (boundary(prev) && !space(prev))
45
			r.start = text_char_next(txt, text_customword_end_prev(txt, pos, isboundary));
32
			r.start = text_customword_start_prev(txt, pos, isboundary);
46
			r.end = text_char_next(txt, text_customword_end_next(txt, pos, isboundary));
33
		else
47
		} else {
48
			/* on a single character */
49
			r.start = pos;
34
			r.start = pos;
35
36
		if (boundary(next) && !space(next))
37
			r.end = text_char_next(txt, text_customword_end_next(txt, pos, isboundary));
38
		else
50
			r.end = text_char_next(txt, pos);
39
			r.end = text_char_next(txt, pos);
51
		}
52
	} else if (boundary(prev)) {
53
		/* at start of a word */
54
		r.start = pos;
55
		r.end = text_char_next(txt, text_customword_end_next(txt, pos, isboundary));
56
	} else if (boundary(next)) {
57
		/* at end of a word */
58
		r.start = text_customword_start_prev(txt, pos, isboundary);
59
		r.end = text_char_next(txt, pos);
60
	} else {
40
	} else {
61
		/* in the middle of a word */
41
		if (boundary(prev))
62
		r.start = text_customword_start_prev(txt, pos, isboundary);
42
			r.start = pos;
63
		r.end = text_char_next(txt, text_customword_end_next(txt, pos, isboundary));
43
		else
44
			r.start = text_customword_start_prev(txt, pos, isboundary);
45
46
		if (boundary(next))
47
			r.end = text_char_next(txt, pos);
48
		else
49
			r.end = text_char_next(txt, text_customword_end_next(txt, pos, isboundary));
64
	}
50
	}
65
51
66
	return r;
52
	return r;
Lines 149-154 Link Here
149
			return text_range_empty();
135
			return text_range_empty();
150
		}
136
		}
151
	}
137
	}
138
}
139
140
Filerange text_object_find_next(Text *txt, size_t pos, const char *search) {
141
	size_t start = text_find_next(txt, pos, search);
142
	if (start == pos)
143
		return text_range_empty();
144
	return text_range_new(start, start+strlen(search));
145
}
146
147
Filerange text_object_find_prev(Text *txt, size_t pos, const char *search) {
148
	size_t start = text_find_prev(txt, pos, search);
149
	if (start == pos)
150
		return text_range_empty();
151
	return text_range_new(start, start+strlen(search));
152
}
152
}
153
153
154
Filerange text_object_line(Text *txt, size_t pos) {
154
Filerange text_object_line(Text *txt, size_t pos) {
(-)vis-0.6/text-objects.h (-7 / +8 lines)
Lines 1-8 Link Here
1
#ifndef TEXT_OBJECTS_H
1
#ifndef TEXT_OBJECTS_H
2
#define TEXT_OBJECTS_H
2
#define TEXT_OBJECTS_H
3
3
4
/* these functions all take a file position. if this position is part of the
4
/* these functions all take a file position. If this position is part of the
5
 * respective text-object, a corresponding range is returned. if there is no
5
 * respective text-object, a corresponding range is returned. If there is no
6
 * such text-object at the given location, an empty range is returned.
6
 * such text-object at the given location, an empty range is returned.
7
 */
7
 */
8
8
Lines 11-26 Link Here
11
11
12
/* return range covering the entire text */
12
/* return range covering the entire text */
13
Filerange text_object_entire(Text*, size_t pos);
13
Filerange text_object_entire(Text*, size_t pos);
14
/* entire document except leading and trailing empty lines */
15
Filerange text_object_entire_inner(Text*, size_t pos);
16
/* word which happens to be at pos without any neighbouring white spaces */
14
/* word which happens to be at pos without any neighbouring white spaces */
17
Filerange text_object_word(Text*, size_t pos);
15
Filerange text_object_word(Text*, size_t pos);
18
/* includes trailing white spaces. if at pos happens to be a white space
16
/* includes trailing white spaces. If at pos happens to be a white space
19
 * include all neighbouring leading white spaces and the following word. */
17
 * include all neighbouring leading white spaces and the following word. */
20
Filerange text_object_word_outer(Text*, size_t pos);
18
Filerange text_object_word_outer(Text*, size_t pos);
21
/* find next occurance of `word' (as word not substring) in forward/backward direction */
19
/* find next occurence of `word' (as word not substring) in forward/backward direction */
22
Filerange text_object_word_find_next(Text*, size_t pos, const char *word);
20
Filerange text_object_word_find_next(Text*, size_t pos, const char *word);
23
Filerange text_object_word_find_prev(Text*, size_t pos, const char *word);
21
Filerange text_object_word_find_prev(Text*, size_t pos, const char *word);
22
/* find next occurence of a literal string (not regex) in forward/backward direction */
23
Filerange text_object_find_next(Text *txt, size_t pos, const char *search);
24
Filerange text_object_find_prev(Text *txt, size_t pos, const char *search);
24
/* same semantics as above but for a longword (i.e. delimited by white spaces) */
25
/* same semantics as above but for a longword (i.e. delimited by white spaces) */
25
Filerange text_object_longword(Text*, size_t pos);
26
Filerange text_object_longword(Text*, size_t pos);
26
Filerange text_object_longword_outer(Text*, size_t pos);
27
Filerange text_object_longword_outer(Text*, size_t pos);
Lines 43-49 Link Here
43
/* match a search term in either forward or backward direction */
44
/* match a search term in either forward or backward direction */
44
Filerange text_object_search_forward(Text*, size_t pos, Regex*);
45
Filerange text_object_search_forward(Text*, size_t pos, Regex*);
45
Filerange text_object_search_backward(Text*, size_t pos, Regex*);
46
Filerange text_object_search_backward(Text*, size_t pos, Regex*);
46
/* match all lines with same indendation level than the current one */
47
/* match all lines with same indentation level as the current one */
47
Filerange text_object_indentation(Text*, size_t pos);
48
Filerange text_object_indentation(Text*, size_t pos);
48
49
49
/* extend a range to cover whole lines */
50
/* extend a range to cover whole lines */
(-)vis-0.6/text.c (-817 / +94 lines)
Lines 1-6 Link Here
1
#ifndef _GNU_SOURCE
2
#define _GNU_SOURCE /* memrchr(3) is non-standard */
3
#endif
4
#include <unistd.h>
1
#include <unistd.h>
5
#include <stdio.h>
2
#include <stdio.h>
6
#include <stdlib.h>
3
#include <stdlib.h>
Lines 15-62 Link Here
15
#include <sys/types.h>
12
#include <sys/types.h>
16
#include <sys/stat.h>
13
#include <sys/stat.h>
17
#include <sys/mman.h>
14
#include <sys/mman.h>
18
#if CONFIG_ACL
19
#include <sys/acl.h>
20
#endif
21
#if CONFIG_SELINUX
22
#include <selinux/selinux.h>
23
#endif
24
15
25
#include "text.h"
16
#include "text.h"
26
#include "text-util.h"
17
#include "text-util.h"
27
#include "text-motions.h"
18
#include "text-motions.h"
28
#include "util.h"
19
#include "util.h"
20
#include "array.h"
21
#include "text-internal.h"
29
22
30
/* Allocate blocks holding the actual file content in junks of size: */
31
#ifndef BLOCK_SIZE
32
#define BLOCK_SIZE (1 << 20)
33
#endif
34
/* Files smaller than this value are copied on load, larger ones are mmap(2)-ed
35
 * directely. Hence the former can be truncated, while doing so on the latter
36
 * results in havoc. */
37
#define BLOCK_MMAP_SIZE (1 << 26)
38
39
/* Block holding the file content, either readonly mmap(2)-ed from the original
40
 * file or heap allocated to store the modifications.
41
 */
42
typedef struct Block Block;
43
struct Block {
44
	size_t size;               /* maximal capacity */
45
	size_t len;                /* current used length / insertion position */
46
	char *data;                /* actual data */
47
	enum {                     /* type of allocation */
48
		MMAP_ORIG,         /* mmap(2)-ed from an external file */
49
		MMAP,              /* mmap(2)-ed from a temporary file only known to this process */
50
		MALLOC,            /* heap allocated block using malloc(3) */
51
	} type;
52
	Block *next;               /* next junk */
53
};
54
55
/* A piece holds a reference (but doesn't itself store) a certain amount of data.
23
/* A piece holds a reference (but doesn't itself store) a certain amount of data.
56
 * All active pieces chained together form the whole content of the document.
24
 * All active pieces chained together form the whole content of the document.
57
 * At the beginning there exists only one piece, spanning the whole document.
25
 * At the beginning there exists only one piece, spanning the whole document.
58
 * Upon insertion/deletion new pieces will be created to represent the changes.
26
 * Upon insertion/deletion new pieces will be created to represent the changes.
59
 * Generally pieces are never destroyed, but kept around to peform undo/redo
27
 * Generally pieces are never destroyed, but kept around to perform undo/redo
60
 * operations.
28
 * operations.
61
 */
29
 */
62
struct Piece {
30
struct Piece {
Lines 115-122 Link Here
115
83
116
/* The main struct holding all information of a given file */
84
/* The main struct holding all information of a given file */
117
struct Text {
85
struct Text {
118
	Block *block;           /* original file content at the time of load operation */
86
	Array blocks;           /* blocks which hold text content */
119
	Block *blocks;          /* all blocks which have been allocated to hold insertion data */
120
	Piece *pieces;          /* all pieces which have been allocated, used to free them */
87
	Piece *pieces;          /* all pieces which have been allocated, used to free them */
121
	Piece *cache;           /* most recently modified piece */
88
	Piece *cache;           /* most recently modified piece */
122
	Piece begin, end;       /* sentinel nodes which always exists but don't hold any data */
89
	Piece begin, end;       /* sentinel nodes which always exists but don't hold any data */
Lines 129-151 Link Here
129
	LineCache lines;        /* mapping between absolute pos in bytes and logical line breaks */
96
	LineCache lines;        /* mapping between absolute pos in bytes and logical line breaks */
130
};
97
};
131
98
132
struct TextSave {                  /* used to hold context between text_save_{begin,commit} calls */
133
	Text *txt;                 /* text to operate on */
134
	char *filename;            /* filename to save to as given to text_save_begin */
135
	char *tmpname;             /* temporary name used for atomic rename(2) */
136
	int fd;                    /* file descriptor to write data to using text_save_write */
137
	enum TextSaveMethod type;  /* method used to save file */
138
};
139
140
/* block management */
99
/* block management */
141
static Block *block_alloc(Text*, size_t size);
142
static Block *block_read(Text*, size_t size, int fd);
143
static Block *block_mmap(Text*, size_t size, int fd, off_t offset);
144
static void block_free(Block*);
145
static bool block_capacity(Block*, size_t len);
146
static const char *block_append(Block*, const char *data, size_t len);
147
static bool block_insert(Block*, size_t pos, const char *data, size_t len);
148
static bool block_delete(Block*, size_t pos, size_t len);
149
static const char *block_store(Text*, const char *data, size_t len);
100
static const char *block_store(Text*, const char *data, size_t len);
150
/* cache layer */
101
/* cache layer */
151
static void cache_piece(Text *txt, Piece *p);
102
static void cache_piece(Text *txt, Piece *p);
Lines 157-163 Link Here
157
static void piece_free(Piece *p);
108
static void piece_free(Piece *p);
158
static void piece_init(Piece *p, Piece *prev, Piece *next, const char *data, size_t len);
109
static void piece_init(Piece *p, Piece *prev, Piece *next, const char *data, size_t len);
159
static Location piece_get_intern(Text *txt, size_t pos);
110
static Location piece_get_intern(Text *txt, size_t pos);
160
static Location piece_get_extern(Text *txt, size_t pos);
111
static Location piece_get_extern(const Text *txt, size_t pos);
161
/* span management */
112
/* span management */
162
static void span_init(Span *span, Piece *start, Piece *end);
113
static void span_init(Span *span, Piece *start, Piece *end);
163
static void span_swap(Text *txt, Span *old, Span *new);
114
static void span_swap(Text *txt, Span *old, Span *new);
Lines 172-316 Link Here
172
static size_t lines_skip_forward(Text *txt, size_t pos, size_t lines, size_t *lines_skiped);
123
static size_t lines_skip_forward(Text *txt, size_t pos, size_t lines, size_t *lines_skiped);
173
static size_t lines_count(Text *txt, size_t pos, size_t len);
124
static size_t lines_count(Text *txt, size_t pos, size_t len);
174
125
175
static ssize_t write_all(int fd, const char *buf, size_t count) {
126
/* stores the given data in a block, allocates a new one if necessary. Returns
176
	size_t rem = count;
127
 * a pointer to the storage location or NULL if allocation failed. */
177
	while (rem > 0) {
128
static const char *block_store(Text *txt, const char *data, size_t len) {
178
		ssize_t written = write(fd, buf, rem > INT_MAX ? INT_MAX : rem);
129
	Block *blk = array_get_ptr(&txt->blocks, array_length(&txt->blocks)-1);
179
		if (written < 0) {
130
	if (!blk || !block_capacity(blk, len)) {
180
			if (errno == EAGAIN || errno == EINTR)
131
		blk = block_alloc(len);
181
				continue;
132
		if (!blk)
182
			return -1;
133
			return NULL;
183
		} else if (written == 0) {
134
		if (!array_add_ptr(&txt->blocks, blk)) {
184
			break;
185
		}
186
		rem -= written;
187
		buf += written;
188
	}
189
	return count - rem;
190
}
191
192
/* allocate a new block of MAX(size, BLOCK_SIZE) bytes */
193
static Block *block_alloc(Text *txt, size_t size) {
194
	Block *blk = calloc(1, sizeof *blk);
195
	if (!blk)
196
		return NULL;
197
	if (BLOCK_SIZE > size)
198
		size = BLOCK_SIZE;
199
	if (!(blk->data = malloc(size))) {
200
		free(blk);
201
		return NULL;
202
	}
203
	blk->type = MALLOC;
204
	blk->size = size;
205
	blk->next = txt->blocks;
206
	txt->blocks = blk;
207
	return blk;
208
}
209
210
static Block *block_read(Text *txt, size_t size, int fd) {
211
	Block *blk = block_alloc(txt, size);
212
	if (!blk)
213
		return NULL;
214
	while (size > 0) {
215
		char data[4096];
216
		ssize_t len = read(fd, data, MIN(sizeof(data), size));
217
		if (len == -1) {
218
			txt->blocks = blk->next;
219
			block_free(blk);
135
			block_free(blk);
220
			return NULL;
136
			return NULL;
221
		} else if (len == 0) {
222
			break;
223
		} else {
224
			block_append(blk, data, len);
225
			size -= len;
226
		}
137
		}
227
	}
138
	}
228
	return blk;
229
}
230
231
static Block *block_mmap(Text *txt, size_t size, int fd, off_t offset) {
232
	Block *blk = calloc(1, sizeof *blk);
233
	if (!blk)
234
		return NULL;
235
	if (size) {
236
		blk->data = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, offset);
237
		if (blk->data == MAP_FAILED) {
238
			free(blk);
239
			return NULL;
240
		}
241
	}
242
	blk->type = MMAP_ORIG;
243
	blk->size = size;
244
	blk->len = size;
245
	blk->next = txt->blocks;
246
	txt->blocks = blk;
247
	return blk;
248
}
249
250
static void block_free(Block *blk) {
251
	if (!blk)
252
		return;
253
	if (blk->type == MALLOC)
254
		free(blk->data);
255
	else if ((blk->type == MMAP_ORIG || blk->type == MMAP) && blk->data)
256
		munmap(blk->data, blk->size);
257
	free(blk);
258
}
259
260
/* check whether block has enough free space to store len bytes */
261
static bool block_capacity(Block *blk, size_t len) {
262
	return blk->size - blk->len >= len;
263
}
264
265
/* append data to block, assumes there is enough space available */
266
static const char *block_append(Block *blk, const char *data, size_t len) {
267
	char *dest = memcpy(blk->data + blk->len, data, len);
268
	blk->len += len;
269
	return dest;
270
}
271
272
/* stores the given data in a block, allocates a new one if necessary. returns
273
 * a pointer to the storage location or NULL if allocation failed. */
274
static const char *block_store(Text *txt, const char *data, size_t len) {
275
	Block *blk = txt->blocks;
276
	if ((!blk || !block_capacity(blk, len)) && !(blk = block_alloc(txt, len)))
277
		return NULL;
278
	return block_append(blk, data, len);
139
	return block_append(blk, data, len);
279
}
140
}
280
141
281
/* insert data into block at an arbitrary position, this should only be used with
282
 * data of the most recently created piece. */
283
static bool block_insert(Block *blk, size_t pos, const char *data, size_t len) {
284
	if (pos > blk->len || !block_capacity(blk, len))
285
		return false;
286
	if (blk->len == pos)
287
		return block_append(blk, data, len);
288
	char *insert = blk->data + pos;
289
	memmove(insert + len, insert, blk->len - pos);
290
	memcpy(insert, data, len);
291
	blk->len += len;
292
	return true;
293
}
294
295
/* delete data from a block at an arbitrary position, this should only be used with
296
 * data of the most recently created piece. */
297
static bool block_delete(Block *blk, size_t pos, size_t len) {
298
	size_t end;
299
	if (!addu(pos, len, &end) || end > blk->len)
300
		return false;
301
	if (blk->len == pos) {
302
		blk->len -= len;
303
		return true;
304
	}
305
	char *delete = blk->data + pos;
306
	memmove(delete, delete + len, blk->len - pos - len);
307
	blk->len -= len;
308
	return true;
309
}
310
311
/* cache the given piece if it is the most recently changed one */
142
/* cache the given piece if it is the most recently changed one */
312
static void cache_piece(Text *txt, Piece *p) {
143
static void cache_piece(Text *txt, Piece *p) {
313
	Block *blk = txt->blocks;
144
	Block *blk = array_get_ptr(&txt->blocks, array_length(&txt->blocks)-1);
314
	if (!blk || p->data < blk->data || p->data + p->len != blk->data + blk->len)
145
	if (!blk || p->data < blk->data || p->data + p->len != blk->data + blk->len)
315
		return;
146
		return;
316
	txt->cache = p;
147
	txt->cache = p;
Lines 318-324 Link Here
318
149
319
/* check whether the given piece was the most recently modified one */
150
/* check whether the given piece was the most recently modified one */
320
static bool cache_contains(Text *txt, Piece *p) {
151
static bool cache_contains(Text *txt, Piece *p) {
321
	Block *blk = txt->blocks;
152
	Block *blk = array_get_ptr(&txt->blocks, array_length(&txt->blocks)-1);
322
	Revision *rev = txt->current_revision;
153
	Revision *rev = txt->current_revision;
323
	if (!blk || !txt->cache || txt->cache != p || !rev || !rev->change)
154
	if (!blk || !txt->cache || txt->cache != p || !rev || !rev->change)
324
		return false;
155
		return false;
Lines 336-348 Link Here
336
	return found && p->data + p->len == blk->data + blk->len;
167
	return found && p->data + p->len == blk->data + blk->len;
337
}
168
}
338
169
339
/* try to insert a junk of data at a given piece offset. the insertion is only
170
/* try to insert a chunk of data at a given piece offset. The insertion is only
340
 * performed if the piece is the most recenetly changed one. the legnth of the
171
 * performed if the piece is the most recently changed one. The length of the
341
 * piece, the span containing it and the whole text is adjusted accordingly */
172
 * piece, the span containing it and the whole text is adjusted accordingly */
342
static bool cache_insert(Text *txt, Piece *p, size_t off, const char *data, size_t len) {
173
static bool cache_insert(Text *txt, Piece *p, size_t off, const char *data, size_t len) {
343
	if (!cache_contains(txt, p))
174
	if (!cache_contains(txt, p))
344
		return false;
175
		return false;
345
	Block *blk = txt->blocks;
176
	Block *blk = array_get_ptr(&txt->blocks, array_length(&txt->blocks)-1);
346
	size_t bufpos = p->data + off - blk->data;
177
	size_t bufpos = p->data + off - blk->data;
347
	if (!block_insert(blk, bufpos, data, len))
178
	if (!block_insert(blk, bufpos, data, len))
348
		return false;
179
		return false;
Lines 352-365 Link Here
352
	return true;
183
	return true;
353
}
184
}
354
185
355
/* try to delete a junk of data at a given piece offset. the deletion is only
186
/* try to delete a chunk of data at a given piece offset. The deletion is only
356
 * performed if the piece is the most recenetly changed one and the whole
187
 * performed if the piece is the most recently changed one and the whole
357
 * affected range lies within it. the legnth of the piece, the span containing it
188
 * affected range lies within it. The length of the piece, the span containing it
358
 * and the whole text is adjusted accordingly */
189
 * and the whole text is adjusted accordingly */
359
static bool cache_delete(Text *txt, Piece *p, size_t off, size_t len) {
190
static bool cache_delete(Text *txt, Piece *p, size_t off, size_t len) {
360
	if (!cache_contains(txt, p))
191
	if (!cache_contains(txt, p))
361
		return false;
192
		return false;
362
	Block *blk = txt->blocks;
193
	Block *blk = array_get_ptr(&txt->blocks, array_length(&txt->blocks)-1);
363
	size_t end;
194
	size_t end;
364
	size_t bufpos = p->data + off - blk->data;
195
	size_t bufpos = p->data + off - blk->data;
365
	if (!addu(off, len, &end) || end > p->len || !block_delete(blk, bufpos, len))
196
	if (!addu(off, len, &end) || end > p->len || !block_delete(blk, bufpos, len))
Lines 485-493 Link Here
485
	p->len = len;
316
	p->len = len;
486
}
317
}
487
318
488
/* returns the piece holding the text at byte offset pos. if pos happens to
319
/* returns the piece holding the text at byte offset pos. If pos happens to
489
 * be at a piece boundry i.e. the first byte of a piece then the previous piece
320
 * be at a piece boundary i.e. the first byte of a piece then the previous piece
490
 * to the left is returned with an offset of piece->len. this is convenient for
321
 * to the left is returned with an offset of piece->len. This is convenient for
491
 * modifications to the piece chain where both pieces (the returned one and the
322
 * modifications to the piece chain where both pieces (the returned one and the
492
 * one following it) are needed, but unsuitable as a public interface.
323
 * one following it) are needed, but unsuitable as a public interface.
493
 *
324
 *
Lines 504-515 Link Here
504
	return (Location){ 0 };
335
	return (Location){ 0 };
505
}
336
}
506
337
507
/* similiar to piece_get_intern but usable as a public API. returns the piece
338
/* similiar to piece_get_intern but usable as a public API. Returns the piece
508
 * holding the text at byte offset pos. never returns a sentinel piece.
339
 * holding the text at byte offset pos. Never returns a sentinel piece.
509
 * it pos is the end of file (== text_size()) and the file is not empty then
340
 * it pos is the end of file (== text_size()) and the file is not empty then
510
 * the last piece holding data is returned.
341
 * the last piece holding data is returned.
511
 */
342
 */
512
static Location piece_get_extern(Text *txt, size_t pos) {
343
static Location piece_get_extern(const Text *txt, size_t pos) {
513
	size_t cur = 0;
344
	size_t cur = 0;
514
	Piece *p;
345
	Piece *p;
515
346
Lines 616-623 Link Here
616
		span_init(&c->new, new, new);
447
		span_init(&c->new, new, new);
617
		span_init(&c->old, NULL, NULL);
448
		span_init(&c->old, NULL, NULL);
618
	} else {
449
	} else {
619
		/* insert into middle of an existing piece, therfore split the old
450
		/* insert into middle of an existing piece, therefore split the old
620
		 * piece. that is we have 3 new pieces one containing the content
451
		 * piece. That is we have 3 new pieces one containing the content
621
		 * before the insertion point then one holding the newly inserted
452
		 * before the insertion point then one holding the newly inserted
622
		 * text and one holding the content after the insertion point.
453
		 * text and one holding the content after the insertion point.
623
		 */
454
		 */
Lines 639-675 Link Here
639
	return true;
470
	return true;
640
}
471
}
641
472
642
static bool text_vprintf(Text *txt, size_t pos, const char *format, va_list ap) {
643
	va_list ap_save;
644
	va_copy(ap_save, ap);
645
	int len = vsnprintf(NULL, 0, format, ap);
646
	if (len == -1) {
647
		va_end(ap_save);
648
		return false;
649
	}
650
	char *buf = malloc(len+1);
651
	bool ret = buf && (vsnprintf(buf, len+1, format, ap_save) == len) && text_insert(txt, pos, buf, len);
652
	free(buf);
653
	va_end(ap_save);
654
	return ret;
655
}
656
657
bool text_appendf(Text *txt, const char *format, ...) {
658
	va_list ap;
659
	va_start(ap, format);
660
	bool ret = text_vprintf(txt, text_size(txt), format, ap);
661
	va_end(ap);
662
	return ret;
663
}
664
665
bool text_printf(Text *txt, size_t pos, const char *format, ...) {
666
	va_list ap;
667
	va_start(ap, format);
668
	bool ret = text_vprintf(txt, pos, format, ap);
669
	va_end(ap);
670
	return ret;
671
}
672
673
static size_t revision_undo(Text *txt, Revision *rev) {
473
static size_t revision_undo(Text *txt, Revision *rev) {
674
	size_t pos = EPOS;
474
	size_t pos = EPOS;
675
	for (Change *c = rev->change; c; c = c->next) {
475
	for (Change *c = rev->change; c; c = c->next) {
Lines 781-1163 Link Here
781
	return history_traverse_to(txt, rev);
581
	return history_traverse_to(txt, rev);
782
}
582
}
783
583
784
time_t text_state(Text *txt) {
584
time_t text_state(const Text *txt) {
785
	return txt->history->time;
585
	return txt->history->time;
786
}
586
}
787
587
788
static bool preserve_acl(int src, int dest) {
588
Text *text_loadat_method(int dirfd, const char *filename, enum TextLoadMethod method) {
789
#if CONFIG_ACL
790
	acl_t acl = acl_get_fd(src);
791
	if (!acl)
792
		return errno == ENOTSUP ? true : false;
793
	if (acl_set_fd(dest, acl) == -1) {
794
		acl_free(acl);
795
		return false;
796
	}
797
	acl_free(acl);
798
#endif /* CONFIG_ACL */
799
	return true;
800
}
801
802
static bool preserve_selinux_context(int src, int dest) {
803
#if CONFIG_SELINUX
804
	char *context = NULL;
805
	if (!is_selinux_enabled())
806
		return true;
807
	if (fgetfilecon(src, &context) == -1)
808
		return errno == ENOTSUP ? true : false;
809
	if (fsetfilecon(dest, context) == -1) {
810
		freecon(context);
811
		return false;
812
	}
813
	freecon(context);
814
#endif /* CONFIG_SELINUX */
815
	return true;
816
}
817
818
/* Create a new file named `.filename.vis.XXXXXX` (where `XXXXXX` is a
819
 * randomly generated, unique suffix) and try to preserve all important
820
 * meta data. After the file content has been written to this temporary
821
 * file, text_save_commit_atomic will atomically move it to  its final
822
 * (possibly already existing) destination using rename(2).
823
 *
824
 * This approach does not work if:
825
 *
826
 *   - the file is a symbolic link
827
 *   - the file is a hard link
828
 *   - file ownership can not be preserved
829
 *   - file group can not be preserved
830
 *   - directory permissions do not allow creation of a new file
831
 *   - POSXI ACL can not be preserved (if enabled)
832
 *   - SELinux security context can not be preserved (if enabled)
833
 */
834
static bool text_save_begin_atomic(TextSave *ctx) {
835
	int oldfd, saved_errno;
836
	if ((oldfd = open(ctx->filename, O_RDONLY)) == -1 && errno != ENOENT)
837
		goto err;
838
	struct stat oldmeta = { 0 };
839
	if (oldfd != -1 && lstat(ctx->filename, &oldmeta) == -1)
840
		goto err;
841
	if (oldfd != -1) {
842
		if (S_ISLNK(oldmeta.st_mode)) /* symbolic link */
843
			goto err;
844
		if (oldmeta.st_nlink > 1) /* hard link */
845
			goto err;
846
	}
847
848
	char suffix[] = ".vis.XXXXXX";
849
	size_t len = strlen(ctx->filename) + sizeof("./.") + sizeof(suffix);
850
	char *dir = strdup(ctx->filename);
851
	char *base = strdup(ctx->filename);
852
853
	if (!(ctx->tmpname = malloc(len)) || !dir || !base) {
854
		free(dir);
855
		free(base);
856
		goto err;
857
	}
858
859
	snprintf(ctx->tmpname, len, "%s/.%s%s", dirname(dir), basename(base), suffix);
860
	free(dir);
861
	free(base);
862
863
	if ((ctx->fd = mkstemp(ctx->tmpname)) == -1)
864
		goto err;
865
866
	if (oldfd == -1) {
867
		mode_t mask = umask(0);
868
		umask(mask);
869
		if (fchmod(ctx->fd, 0666 & ~mask) == -1)
870
			goto err;
871
	} else {
872
		if (fchmod(ctx->fd, oldmeta.st_mode) == -1)
873
			goto err;
874
		if (!preserve_acl(oldfd, ctx->fd) || !preserve_selinux_context(oldfd, ctx->fd))
875
			goto err;
876
		/* change owner if necessary */
877
		if (oldmeta.st_uid != getuid() && fchown(ctx->fd, oldmeta.st_uid, (uid_t)-1) == -1)
878
			goto err;
879
		/* change group if necessary, in case of failure some editors reset
880
		 * the group permissions to the same as for others */
881
		if (oldmeta.st_gid != getgid() && fchown(ctx->fd, (uid_t)-1, oldmeta.st_gid) == -1)
882
			goto err;
883
		close(oldfd);
884
	}
885
886
	ctx->type = TEXT_SAVE_ATOMIC;
887
	return true;
888
err:
889
	saved_errno = errno;
890
	if (oldfd != -1)
891
		close(oldfd);
892
	if (ctx->fd != -1)
893
		close(ctx->fd);
894
	ctx->fd = -1;
895
	free(ctx->tmpname);
896
	ctx->tmpname = NULL;
897
	errno = saved_errno;
898
	return false;
899
}
900
901
static bool text_save_commit_atomic(TextSave *ctx) {
902
	if (fsync(ctx->fd) == -1)
903
		return false;
904
905
	struct stat meta = { 0 };
906
	if (fstat(ctx->fd, &meta) == -1)
907
		return false;
908
909
	bool close_failed = (close(ctx->fd) == -1);
910
	ctx->fd = -1;
911
	if (close_failed)
912
		return false;
913
914
	if (rename(ctx->tmpname, ctx->filename) == -1)
915
		return false;
916
917
	free(ctx->tmpname);
918
	ctx->tmpname = NULL;
919
920
	int dir = open(dirname(ctx->filename), O_DIRECTORY|O_RDONLY);
921
	if (dir == -1)
922
		return false;
923
924
	if (fsync(dir) == -1 && errno != EINVAL) {
925
		close(dir);
926
		return false;
927
	}
928
929
	if (close(dir) == -1)
930
		return false;
931
932
	if (meta.st_mtime)
933
		ctx->txt->info = meta;
934
	return true;
935
}
936
937
static bool text_save_begin_inplace(TextSave *ctx) {
938
	Text *txt = ctx->txt;
939
	struct stat meta = { 0 };
940
	int newfd = -1, saved_errno;
941
	if ((ctx->fd = open(ctx->filename, O_CREAT|O_WRONLY, 0666)) == -1)
942
		goto err;
943
	if (fstat(ctx->fd, &meta) == -1)
944
		goto err;
945
	if (meta.st_dev == txt->info.st_dev && meta.st_ino == txt->info.st_ino &&
946
	    txt->block && txt->block->type == MMAP_ORIG && txt->block->size) {
947
		/* The file we are going to overwrite is currently mmap-ed from
948
		 * text_load, therefore we copy the mmap-ed block to a temporary
949
		 * file and remap it at the same position such that all pointers
950
		 * from the various pieces are still valid.
951
		 */
952
		size_t size = txt->block->size;
953
		char tmpname[32] = "/tmp/vis-XXXXXX";
954
		newfd = mkstemp(tmpname);
955
		if (newfd == -1)
956
			goto err;
957
		if (unlink(tmpname) == -1)
958
			goto err;
959
		ssize_t written = write_all(newfd, txt->block->data, size);
960
		if (written == -1 || (size_t)written != size)
961
			goto err;
962
		if (munmap(txt->block->data, size) == -1)
963
			goto err;
964
965
		void *data = mmap(txt->block->data, size, PROT_READ, MAP_SHARED, newfd, 0);
966
		if (data == MAP_FAILED)
967
			goto err;
968
		if (data != txt->block->data) {
969
			munmap(data, size);
970
			goto err;
971
		}
972
		bool close_failed = (close(newfd) == -1);
973
		newfd = -1;
974
		if (close_failed)
975
			goto err;
976
		txt->block->data = data;
977
		txt->block->type = MMAP;
978
		newfd = -1;
979
	}
980
	/* overwrite the existing file content, if something goes wrong
981
	 * here we are screwed, TODO: make a backup before? */
982
	if (ftruncate(ctx->fd, 0) == -1)
983
		goto err;
984
	ctx->type = TEXT_SAVE_INPLACE;
985
	return true;
986
err:
987
	saved_errno = errno;
988
	if (newfd != -1)
989
		close(newfd);
990
	if (ctx->fd != -1)
991
		close(ctx->fd);
992
	ctx->fd = -1;
993
	errno = saved_errno;
994
	return false;
995
}
996
997
static bool text_save_commit_inplace(TextSave *ctx) {
998
	if (fsync(ctx->fd) == -1)
999
		return false;
1000
	struct stat meta = { 0 };
1001
	if (fstat(ctx->fd, &meta) == -1)
1002
		return false;
1003
	if (close(ctx->fd) == -1)
1004
		return false;
1005
	ctx->txt->info = meta;
1006
	return true;
1007
}
1008
1009
TextSave *text_save_begin(Text *txt, const char *filename, enum TextSaveMethod type) {
1010
	if (!filename)
1011
		return NULL;
1012
	TextSave *ctx = calloc(1, sizeof *ctx);
1013
	if (!ctx)
1014
		return NULL;
1015
	ctx->txt = txt;
1016
	ctx->fd = -1;
1017
	if (!(ctx->filename = strdup(filename)))
1018
		goto err;
1019
	errno = 0;
1020
	if ((type == TEXT_SAVE_AUTO || type == TEXT_SAVE_ATOMIC) && text_save_begin_atomic(ctx))
1021
		return ctx;
1022
	if (errno == ENOSPC)
1023
		goto err;
1024
	if ((type == TEXT_SAVE_AUTO || type == TEXT_SAVE_INPLACE) && text_save_begin_inplace(ctx))
1025
		return ctx;
1026
err:
1027
	text_save_cancel(ctx);
1028
	return NULL;
1029
}
1030
1031
bool text_save_commit(TextSave *ctx) {
1032
	if (!ctx)
1033
		return true;
1034
	bool ret;
1035
	Text *txt = ctx->txt;
1036
	switch (ctx->type) {
1037
	case TEXT_SAVE_ATOMIC:
1038
		ret = text_save_commit_atomic(ctx);
1039
		break;
1040
	case TEXT_SAVE_INPLACE:
1041
		ret = text_save_commit_inplace(ctx);
1042
		break;
1043
	default:
1044
		ret = false;
1045
		break;
1046
	}
1047
1048
	if (ret) {
1049
		txt->saved_revision = txt->history;
1050
		text_snapshot(txt);
1051
	}
1052
	text_save_cancel(ctx);
1053
	return ret;
1054
}
1055
1056
void text_save_cancel(TextSave *ctx) {
1057
	if (!ctx)
1058
		return;
1059
	int saved_errno = errno;
1060
	if (ctx->fd != -1)
1061
		close(ctx->fd);
1062
	if (ctx->tmpname && ctx->tmpname[0])
1063
		unlink(ctx->tmpname);
1064
	free(ctx->tmpname);
1065
	free(ctx->filename);
1066
	free(ctx);
1067
	errno = saved_errno;
1068
}
1069
1070
/* First try to save the file atomically using rename(2) if this does not
1071
 * work overwrite the file in place. However if something goes wrong during
1072
 * this overwrite the original file is permanently damaged.
1073
 */
1074
bool text_save(Text *txt, const char *filename) {
1075
	return text_save_method(txt, filename, TEXT_SAVE_AUTO);
1076
}
1077
1078
bool text_save_method(Text *txt, const char *filename, enum TextSaveMethod method) {
1079
	if (!filename) {
1080
		txt->saved_revision = txt->history;
1081
		text_snapshot(txt);
1082
		return true;
1083
	}
1084
	TextSave *ctx = text_save_begin(txt, filename, method);
1085
	if (!ctx)
1086
		return false;
1087
	Filerange range = (Filerange){ .start = 0, .end = text_size(txt) };
1088
	ssize_t written = text_save_write_range(ctx, &range);
1089
	if (written == -1 || (size_t)written != text_range_size(&range)) {
1090
		text_save_cancel(ctx);
1091
		return false;
1092
	}
1093
	return text_save_commit(ctx);
1094
}
1095
1096
ssize_t text_save_write_range(TextSave *ctx, Filerange *range) {
1097
	return text_write_range(ctx->txt, range, ctx->fd);
1098
}
1099
1100
ssize_t text_write(Text *txt, int fd) {
1101
	Filerange r = (Filerange){ .start = 0, .end = text_size(txt) };
1102
	return text_write_range(txt, &r, fd);
1103
}
1104
1105
ssize_t text_write_range(Text *txt, Filerange *range, int fd) {
1106
	size_t size = text_range_size(range), rem = size;
1107
	for (Iterator it = text_iterator_get(txt, range->start);
1108
	     rem > 0 && text_iterator_valid(&it);
1109
	     text_iterator_next(&it)) {
1110
		size_t prem = it.end - it.text;
1111
		if (prem > rem)
1112
			prem = rem;
1113
		ssize_t written = write_all(fd, it.text, prem);
1114
		if (written == -1)
1115
			return -1;
1116
		rem -= written;
1117
		if ((size_t)written != prem)
1118
			break;
1119
	}
1120
	return size - rem;
1121
}
1122
1123
Text *text_load(const char *filename) {
1124
	return text_load_method(filename, TEXT_LOAD_AUTO);
1125
}
1126
1127
Text *text_load_method(const char *filename, enum TextLoadMethod method) {
1128
	int fd = -1;
1129
	size_t size = 0;
1130
	Text *txt = calloc(1, sizeof *txt);
589
	Text *txt = calloc(1, sizeof *txt);
1131
	if (!txt)
590
	if (!txt)
1132
		return NULL;
591
		return NULL;
1133
	Piece *p = piece_alloc(txt);
592
	Piece *p = piece_alloc(txt);
1134
	if (!p)
593
	if (!p)
1135
		goto out;
594
		goto out;
595
	Block *block = NULL;
596
	array_init(&txt->blocks);
1136
	lineno_cache_invalidate(&txt->lines);
597
	lineno_cache_invalidate(&txt->lines);
1137
	if (filename) {
598
	if (filename) {
1138
		if ((fd = open(filename, O_RDONLY)) == -1)
599
		errno = 0;
600
		block = block_load(dirfd, filename, method, &txt->info);
601
		if (!block && errno)
1139
			goto out;
602
			goto out;
1140
		if (fstat(fd, &txt->info) == -1)
603
		if (block && !array_add_ptr(&txt->blocks, block)) {
604
			block_free(block);
1141
			goto out;
605
			goto out;
1142
		if (!S_ISREG(txt->info.st_mode)) {
1143
			errno = S_ISDIR(txt->info.st_mode) ? EISDIR : ENOTSUP;
1144
			goto out;
1145
		}
606
		}
1146
		// XXX: use lseek(fd, 0, SEEK_END); instead?
1147
		size = txt->info.st_size;
1148
		if (size > 0) {
1149
			if (method == TEXT_LOAD_READ || (method == TEXT_LOAD_AUTO && size < BLOCK_MMAP_SIZE))
1150
				txt->block = block_read(txt, size, fd);
1151
			else
1152
				txt->block = block_mmap(txt, size, fd, 0);
1153
			if (!txt->block)
1154
				goto out;
1155
			piece_init(p, &txt->begin, &txt->end, txt->block->data, txt->block->len);
1156
		}
1157
	}
607
	}
1158
608
1159
	if (size == 0)
609
	if (!block)
1160
		piece_init(p, &txt->begin, &txt->end, "\0", 0);
610
		piece_init(p, &txt->begin, &txt->end, "\0", 0);
611
	else
612
		piece_init(p, &txt->begin, &txt->end, block->data, block->len);
1161
613
1162
	piece_init(&txt->begin, NULL, p, NULL, 0);
614
	piece_init(&txt->begin, NULL, p, NULL, 0);
1163
	piece_init(&txt->end, p, NULL, NULL, 0);
615
	piece_init(&txt->end, p, NULL, NULL, 0);
Lines 1167-1188 Link Here
1167
	text_snapshot(txt);
619
	text_snapshot(txt);
1168
	txt->saved_revision = txt->history;
620
	txt->saved_revision = txt->history;
1169
621
1170
	if (fd != -1)
1171
		close(fd);
1172
	return txt;
622
	return txt;
1173
out:
623
out:
1174
	if (fd != -1)
1175
		close(fd);
1176
	text_free(txt);
624
	text_free(txt);
1177
	return NULL;
625
	return NULL;
1178
}
626
}
1179
627
1180
struct stat text_stat(Text *txt) {
628
struct stat text_stat(const Text *txt) {
1181
	return txt->info;
629
	return txt->info;
1182
}
630
}
1183
631
632
void text_saved(Text *txt, struct stat *meta) {
633
	if (meta)
634
		txt->info = *meta;
635
	txt->saved_revision = txt->history;
636
	text_snapshot(txt);
637
}
638
639
Block *text_block_mmaped(Text *txt) {
640
	Block *block = array_get_ptr(&txt->blocks, 0);
641
	if (block && block->type == BLOCK_TYPE_MMAP_ORIG && block->size)
642
		return block;
643
	return NULL;
644
}
645
1184
/* A delete operation can either start/stop midway through a piece or at
646
/* A delete operation can either start/stop midway through a piece or at
1185
 * a boundry. In the former case a new piece is created to represent the
647
 * a boundary. In the former case a new piece is created to represent the
1186
 * remaining text before/after the modification point.
648
 * remaining text before/after the modification point.
1187
 *
649
 *
1188
 *      /-+ --> +---------+ --> +-----+ --> +-----+ --> +-\
650
 *      /-+ --> +---------+ --> +-----+ --> +-----+ --> +-\
Lines 1221-1227 Link Here
1221
	size_t cur;            /* how much has already been deleted */
683
	size_t cur;            /* how much has already been deleted */
1222
684
1223
	if (off == p->len) {
685
	if (off == p->len) {
1224
		/* deletion starts at a piece boundry */
686
		/* deletion starts at a piece boundary */
1225
		cur = 0;
687
		cur = 0;
1226
		before = p;
688
		before = p;
1227
		start = p->next;
689
		start = p->next;
Lines 1242-1248 Link Here
1242
	}
704
	}
1243
705
1244
	if (cur == len) {
706
	if (cur == len) {
1245
		/* deletion stops at a piece boundry */
707
		/* deletion stops at a piece boundary */
1246
		end = p;
708
		end = p;
1247
		after = p->next;
709
		after = p->next;
1248
	} else {
710
	} else {
Lines 1278-1284 Link Here
1278
	return true;
740
	return true;
1279
}
741
}
1280
742
1281
bool text_delete_range(Text *txt, Filerange *r) {
743
bool text_delete_range(Text *txt, const Filerange *r) {
1282
	if (!text_range_valid(r))
744
	if (!text_range_valid(r))
1283
		return false;
745
		return false;
1284
	return text_delete(txt, r->start, text_range_size(r));
746
	return text_delete(txt, r->start, text_range_size(r));
Lines 1286-1296 Link Here
1286
748
1287
/* preserve the current text content such that it can be restored by
749
/* preserve the current text content such that it can be restored by
1288
 * means of undo/redo operations */
750
 * means of undo/redo operations */
1289
void text_snapshot(Text *txt) {
751
bool text_snapshot(Text *txt) {
1290
	if (txt->current_revision)
752
	if (txt->current_revision)
1291
		txt->last_revision = txt->current_revision;
753
		txt->last_revision = txt->current_revision;
1292
	txt->current_revision = NULL;
754
	txt->current_revision = NULL;
1293
	txt->cache = NULL;
755
	txt->cache = NULL;
756
	return true;
1294
}
757
}
1295
758
1296
759
Lines 1313-1577 Link Here
1313
		piece_free(p);
776
		piece_free(p);
1314
	}
777
	}
1315
778
1316
	for (Block *next, *blk = txt->blocks; blk; blk = next) {
779
	for (size_t i = 0, len = array_length(&txt->blocks); i < len; i++)
1317
		next = blk->next;
780
		block_free(array_get_ptr(&txt->blocks, i));
1318
		block_free(blk);
781
	array_release(&txt->blocks);
1319
	}
1320
782
1321
	free(txt);
783
	free(txt);
1322
}
784
}
1323
785
1324
bool text_modified(Text *txt) {
786
bool text_modified(const Text *txt) {
1325
	return txt->saved_revision != txt->history;
787
	return txt->saved_revision != txt->history;
1326
}
788
}
1327
789
1328
bool text_mmaped(Text *txt, const char *ptr) {
790
bool text_mmaped(const Text *txt, const char *ptr) {
1329
	uintptr_t addr = (uintptr_t)ptr;
791
	uintptr_t addr = (uintptr_t)ptr;
1330
	for (Block *blk = txt->blocks; blk; blk = blk->next) {
792
	for (size_t i = 0, len = array_length(&txt->blocks); i < len; i++) {
1331
		if ((blk->type == MMAP_ORIG || blk->type == MMAP) &&
793
		Block *blk = array_get_ptr(&txt->blocks, i);
794
		if ((blk->type == BLOCK_TYPE_MMAP_ORIG || blk->type == BLOCK_TYPE_MMAP) &&
1332
		    (uintptr_t)(blk->data) <= addr && addr < (uintptr_t)(blk->data + blk->size))
795
		    (uintptr_t)(blk->data) <= addr && addr < (uintptr_t)(blk->data + blk->size))
1333
			return true;
796
			return true;
1334
	}
797
	}
1335
	return false;
798
	return false;
1336
}
799
}
1337
800
1338
static bool text_iterator_init(Iterator *it, size_t pos, Piece *p, size_t off) {
801
static bool iterator_init(Iterator *it, size_t pos, Piece *p, size_t off) {
1339
	Iterator iter = (Iterator){
802
	*it = (Iterator){
1340
		.pos = pos,
803
		.pos = pos,
1341
		.piece = p,
804
		.piece = p,
1342
		.start = p ? p->data : NULL,
805
		.start = p ? p->data : NULL,
1343
		.end = p ? p->data + p->len : NULL,
806
		.end = p && p->data ? p->data + p->len : NULL,
1344
		.text = p ? p->data + off : NULL,
807
		.text = p && p->data ? p->data + off : NULL,
1345
	};
808
	};
1346
	*it = iter;
1347
	return text_iterator_valid(it);
809
	return text_iterator_valid(it);
1348
}
810
}
1349
811
1350
Iterator text_iterator_get(Text *txt, size_t pos) {
812
bool text_iterator_init(const Text *txt, Iterator *it, size_t pos) {
1351
	Iterator it;
1352
	Location loc = piece_get_extern(txt, pos);
813
	Location loc = piece_get_extern(txt, pos);
1353
	text_iterator_init(&it, pos, loc.piece, loc.off);
814
	return iterator_init(it, pos, loc.piece, loc.off);
1354
	return it;
1355
}
815
}
1356
816
1357
bool text_iterator_byte_get(Iterator *it, char *b) {
817
Iterator text_iterator_get(const Text *txt, size_t pos) {
1358
	if (text_iterator_valid(it)) {
818
	Iterator it;
1359
		if (it->start <= it->text && it->text < it->end) {
819
	text_iterator_init(txt, &it, pos);
1360
			*b = *it->text;
820
	return it;
1361
			return true;
1362
		} else if (it->pos == it->piece->text->size) { /* EOF */
1363
			*b = '\0';
1364
			return true;
1365
		}
1366
	}
1367
	return false;
1368
}
821
}
1369
822
1370
bool text_iterator_next(Iterator *it) {
823
bool text_iterator_next(Iterator *it) {
1371
	size_t rem = it->end - it->text;
824
	size_t rem = it->end - it->text;
1372
	return text_iterator_init(it, it->pos+rem, it->piece ? it->piece->next : NULL, 0);
825
	return iterator_init(it, it->pos+rem, it->piece ? it->piece->next : NULL, 0);
1373
}
826
}
1374
827
1375
bool text_iterator_prev(Iterator *it) {
828
bool text_iterator_prev(Iterator *it) {
1376
	size_t off = it->text - it->start;
829
	size_t off = it->text - it->start;
1377
	size_t len = it->piece && it->piece->prev ? it->piece->prev->len : 0;
830
	size_t len = it->piece && it->piece->prev ? it->piece->prev->len : 0;
1378
	return text_iterator_init(it, it->pos-off, it->piece ? it->piece->prev : NULL, len);
831
	return iterator_init(it, it->pos-off, it->piece ? it->piece->prev : NULL, len);
1379
}
832
}
1380
833
834
const Text *text_iterator_text(const Iterator *it) {
835
	return it->piece ? it->piece->text : NULL;
836
}
837
1381
bool text_iterator_valid(const Iterator *it) {
838
bool text_iterator_valid(const Iterator *it) {
1382
	/* filter out sentinel nodes */
839
	/* filter out sentinel nodes */
1383
	return it->piece && it->piece->text;
840
	return it->piece && it->piece->text;
1384
}
841
}
1385
842
1386
bool text_iterator_byte_next(Iterator *it, char *b) {
843
bool text_iterator_has_next(const Iterator *it) {
1387
	if (!it->piece || !it->piece->next)
844
	return it->piece && it->piece->next;
1388
		return false;
1389
	bool eof = true;
1390
	if (it->text < it->end) {
1391
		it->text++;
1392
		it->pos++;
1393
		eof = false;
1394
	} else if (!it->piece->prev) {
1395
		eof = false;
1396
	}
1397
1398
	while (it->text == it->end) {
1399
		if (!text_iterator_next(it)) {
1400
			if (eof)
1401
				return false;
1402
			if (b)
1403
				*b = '\0';
1404
			return text_iterator_prev(it);
1405
		}
1406
	}
1407
1408
	if (b)
1409
		*b = *it->text;
1410
	return true;
1411
}
845
}
1412
846
1413
bool text_iterator_byte_prev(Iterator *it, char *b) {
847
bool text_iterator_has_prev(const Iterator *it) {
1414
	if (!it->piece || !it->piece->prev)
848
	return it->piece && it->piece->prev;
1415
		return false;
1416
	bool eof = !it->piece->next;
1417
	while (it->text == it->start) {
1418
		if (!text_iterator_prev(it)) {
1419
			if (!eof)
1420
				return false;
1421
			if (b)
1422
				*b = '\0';
1423
			return text_iterator_next(it);
1424
		}
1425
	}
1426
1427
	--it->text;
1428
	--it->pos;
1429
1430
	if (b)
1431
		*b = *it->text;
1432
	return true;
1433
}
849
}
1434
850
1435
bool text_iterator_byte_find_prev(Iterator *it, char b) {
851
size_t text_size(const Text *txt) {
1436
	while (it->text) {
1437
		const char *match = memrchr(it->start, b, it->text - it->start);
1438
		if (match) {
1439
			it->pos -= it->text - match;
1440
			it->text = match;
1441
			return true;
1442
		}
1443
		text_iterator_prev(it);
1444
	}
1445
	text_iterator_next(it);
1446
	return false;
1447
}
1448
1449
bool text_iterator_byte_find_next(Iterator *it, char b) {
1450
	while (it->text) {
1451
		const char *match = memchr(it->text, b, it->end - it->text);
1452
		if (match) {
1453
			it->pos += match - it->text;
1454
			it->text = match;
1455
			return true;
1456
		}
1457
		text_iterator_next(it);
1458
	}
1459
	text_iterator_prev(it);
1460
	return false;
1461
}
1462
1463
bool text_iterator_codepoint_next(Iterator *it, char *c) {
1464
	while (text_iterator_byte_next(it, NULL)) {
1465
		if (ISUTF8(*it->text)) {
1466
			if (c)
1467
				*c = *it->text;
1468
			return true;
1469
		}
1470
	}
1471
	return false;
1472
}
1473
1474
bool text_iterator_codepoint_prev(Iterator *it, char *c) {
1475
	while (text_iterator_byte_prev(it, NULL)) {
1476
		if (ISUTF8(*it->text)) {
1477
			if (c)
1478
				*c = *it->text;
1479
			return true;
1480
		}
1481
	}
1482
	return false;
1483
}
1484
1485
bool text_iterator_char_next(Iterator *it, char *c) {
1486
	if (!text_iterator_codepoint_next(it, c))
1487
		return false;
1488
	mbstate_t ps = { 0 };
1489
	for (;;) {
1490
		char buf[MB_LEN_MAX];
1491
		size_t len = text_bytes_get(it->piece->text, it->pos, sizeof buf, buf);
1492
		wchar_t wc;
1493
		size_t wclen = mbrtowc(&wc, buf, len, &ps);
1494
		if (wclen == (size_t)-1 && errno == EILSEQ) {
1495
			return true;
1496
		} else if (wclen == (size_t)-2) {
1497
			return false;
1498
		} else if (wclen == 0) {
1499
			return true;
1500
		} else {
1501
			int width = wcwidth(wc);
1502
			if (width != 0)
1503
				return true;
1504
			if (!text_iterator_codepoint_next(it, c))
1505
				return false;
1506
		}
1507
	}
1508
	return true;
1509
}
1510
1511
bool text_iterator_char_prev(Iterator *it, char *c) {
1512
	if (!text_iterator_codepoint_prev(it, c))
1513
		return false;
1514
	for (;;) {
1515
		char buf[MB_LEN_MAX];
1516
		size_t len = text_bytes_get(it->piece->text, it->pos, sizeof buf, buf);
1517
		wchar_t wc;
1518
		mbstate_t ps = { 0 };
1519
		size_t wclen = mbrtowc(&wc, buf, len, &ps);
1520
		if (wclen == (size_t)-1 && errno == EILSEQ) {
1521
			return true;
1522
		} else if (wclen == (size_t)-2) {
1523
			return false;
1524
		} else if (wclen == 0) {
1525
			return true;
1526
		} else {
1527
			int width = wcwidth(wc);
1528
			if (width != 0)
1529
				return true;
1530
			if (!text_iterator_codepoint_prev(it, c))
1531
				return false;
1532
		}
1533
	}
1534
	return true;
1535
}
1536
1537
bool text_byte_get(Text *txt, size_t pos, char *byte) {
1538
	return text_bytes_get(txt, pos, 1, byte);
1539
}
1540
1541
size_t text_bytes_get(Text *txt, size_t pos, size_t len, char *buf) {
1542
	if (!buf)
1543
		return 0;
1544
	char *cur = buf;
1545
	size_t rem = len;
1546
	for (Iterator it = text_iterator_get(txt, pos);
1547
	     text_iterator_valid(&it);
1548
	     text_iterator_next(&it)) {
1549
		if (rem == 0)
1550
			break;
1551
		size_t piece_len = it.end - it.text;
1552
		if (piece_len > rem)
1553
			piece_len = rem;
1554
		if (piece_len) {
1555
			memcpy(cur, it.text, piece_len);
1556
			cur += piece_len;
1557
			rem -= piece_len;
1558
		}
1559
	}
1560
	return len - rem;
1561
}
1562
1563
char *text_bytes_alloc0(Text *txt, size_t pos, size_t len) {
1564
	if (len == SIZE_MAX)
1565
		return NULL;
1566
	char *buf = malloc(len+1);
1567
	if (!buf)
1568
		return NULL;
1569
	len = text_bytes_get(txt, pos, len, buf);
1570
	buf[len] = '\0';
1571
	return buf;
1572
}
1573
1574
size_t text_size(Text *txt) {
1575
	return txt->size;
852
	return txt->size;
1576
}
853
}
1577
854
Lines 1680-1686 Link Here
1680
	return (Mark)(loc.piece->data + loc.off);
957
	return (Mark)(loc.piece->data + loc.off);
1681
}
958
}
1682
959
1683
size_t text_mark_get(Text *txt, Mark mark) {
960
size_t text_mark_get(const Text *txt, Mark mark) {
1684
	size_t cur = 0;
961
	size_t cur = 0;
1685
962
1686
	if (mark == EMARK)
963
	if (mark == EMARK)
(-)vis-0.6/text.h (-44 / +52 lines)
Lines 12-18 Link Here
12
/** A mark. */
12
/** A mark. */
13
typedef uintptr_t Mark;
13
typedef uintptr_t Mark;
14
14
15
/** An invalid mark, lookup of which will yield `EPOS`. */
15
/** An invalid mark, lookup of which will yield ``EPOS``. */
16
#define EMARK ((Mark)0)
16
#define EMARK ((Mark)0)
17
/** An invalid position. */
17
/** An invalid position. */
18
#define EPOS ((size_t)-1)
18
#define EPOS ((size_t)-1)
Lines 75-87 Link Here
75
	 */
75
	 */
76
	TEXT_LOAD_READ,
76
	TEXT_LOAD_READ,
77
	/**
77
	/**
78
	 * Memory map the the file from disk. Use file system / virtual memory
78
	 * Memory map the file from disk. Use file system / virtual memory
79
	 * subsystem as a caching layer.
79
	 * subsystem as a caching layer.
80
	 * @rst
80
	 * @rst
81
	 * .. note:: Load time is (almost) independent of the file size.
81
	 * .. note:: Load time is (almost) independent of the file size.
82
	 * .. warning:: Inplace modifications of the underlying file
82
	 * .. warning:: Inplace modifications of the underlying file
83
	 *              will be reflected in the current text content.
83
	 *              will be reflected in the current text content.
84
	 *              In particular, truncatenation will raise ``SIGBUS``
84
	 *              In particular, truncation will raise ``SIGBUS``
85
	 *              and result in data loss.
85
	 *              and result in data loss.
86
	 * @endrst
86
	 * @endrst
87
	 */
87
	 */
Lines 95-100 Link Here
95
 * @endrst
95
 * @endrst
96
 */
96
 */
97
Text *text_load(const char *filename);
97
Text *text_load(const char *filename);
98
Text *text_loadat(int dirfd, const char *filename);
98
/**
99
/**
99
 * Create a text instance populated with the given file content.
100
 * Create a text instance populated with the given file content.
100
 *
101
 *
Lines 109-115 Link Here
109
 * @endrst
110
 * @endrst
110
 */
111
 */
111
Text *text_load_method(const char *filename, enum TextLoadMethod);
112
Text *text_load_method(const char *filename, enum TextLoadMethod);
112
/** Release all ressources associated with this text instance. */
113
Text *text_loadat_method(int dirfd, const char *filename, enum TextLoadMethod);
114
/** Release all resources associated with this text instance. */
113
void text_free(Text*);
115
void text_free(Text*);
114
/**
116
/**
115
 * @}
117
 * @}
Lines 117-123 Link Here
117
 * @{
119
 * @{
118
 */
120
 */
119
/** Return the size in bytes of the whole text. */
121
/** Return the size in bytes of the whole text. */
120
size_t text_size(Text*);
122
size_t text_size(const Text*);
121
/**
123
/**
122
 * Get file information at time of load or last save, whichever happened more
124
 * Get file information at time of load or last save, whichever happened more
123
 * recently.
125
 * recently.
Lines 128-136 Link Here
128
 * @endrst
130
 * @endrst
129
 * @return See ``stat(2)`` for details.
131
 * @return See ``stat(2)`` for details.
130
 */
132
 */
131
struct stat text_stat(Text*);
133
struct stat text_stat(const Text*);
132
/** Query whether the text contains any unsaved modifications. */
134
/** Query whether the text contains any unsaved modifications. */
133
bool text_modified(Text*);
135
bool text_modified(const Text*);
134
/**
136
/**
135
 * @}
137
 * @}
136
 * @defgroup modify
138
 * @defgroup modify
Lines 153-159 Link Here
153
 * @return Whether the deletion succeeded.
155
 * @return Whether the deletion succeeded.
154
 */
156
 */
155
bool text_delete(Text*, size_t pos, size_t len);
157
bool text_delete(Text*, size_t pos, size_t len);
156
bool text_delete_range(Text*, Filerange*);
158
bool text_delete_range(Text*, const Filerange*);
157
bool text_printf(Text*, size_t pos, const char *format, ...) __attribute__((format(printf, 3, 4)));
159
bool text_printf(Text*, size_t pos, const char *format, ...) __attribute__((format(printf, 3, 4)));
158
bool text_appendf(Text*, const char *format, ...) __attribute__((format(printf, 2, 3)));
160
bool text_appendf(Text*, const char *format, ...) __attribute__((format(printf, 2, 3)));
159
/**
161
/**
Lines 162-170 Link Here
162
 * @{
164
 * @{
163
 */
165
 */
164
/**
166
/**
165
 * Create a text snapshot, that is a vertice in the history graph.
167
 * Create a text snapshot, that is a vertex in the history graph.
166
 */
168
 */
167
void text_snapshot(Text*);
169
bool text_snapshot(Text*);
168
/**
170
/**
169
 * Revert to previous snapshot along the main branch.
171
 * Revert to previous snapshot along the main branch.
170
 * @rst
172
 * @rst
Lines 195-201 Link Here
195
 * .. note:: TODO: This is currently not the same as the time of the last snapshot.
197
 * .. note:: TODO: This is currently not the same as the time of the last snapshot.
196
 * @endrst
198
 * @endrst
197
 */
199
 */
198
time_t text_state(Text*);
200
time_t text_state(const Text*);
199
/**
201
/**
200
 * @}
202
 * @}
201
 * @defgroup lines
203
 * @defgroup lines
Lines 219-227 Link Here
219
 *           return an artificial NUL byte at EOF.
221
 *           return an artificial NUL byte at EOF.
220
 * @endrst
222
 * @endrst
221
 */
223
 */
222
bool text_byte_get(Text*, size_t pos, char *byte);
224
bool text_byte_get(const Text*, size_t pos, char *byte);
223
/**
225
/**
224
 * Store at most `len` bytes starting from ``pos`` into ``buf``.
226
 * Store at most ``len`` bytes starting from ``pos`` into ``buf``.
225
 * @param pos The absolute starting position.
227
 * @param pos The absolute starting position.
226
 * @param len The length in bytes.
228
 * @param len The length in bytes.
227
 * @param buf The destination buffer.
229
 * @param buf The destination buffer.
Lines 230-254 Link Here
230
 * .. warning:: ``buf`` will not be NUL terminated.
232
 * .. warning:: ``buf`` will not be NUL terminated.
231
 * @endrst
233
 * @endrst
232
 */
234
 */
233
size_t text_bytes_get(Text*, size_t pos, size_t len, char *buf);
235
size_t text_bytes_get(const Text*, size_t pos, size_t len, char *buf);
234
/**
236
/**
235
 * Fetch text range into newly allocate memory region.
237
 * Fetch text range into newly allocate memory region.
236
 * @param pos The absolute starting position.
238
 * @param pos The absolute starting position.
237
 * @param len The length in bytes.
239
 * @param len The length in bytes.
238
 * @return A contigious NUL terminated buffer holding the requested range, or
240
 * @return A contiguous NUL terminated buffer holding the requested range, or
239
 *         ``NULL`` in error case.
241
 *         ``NULL`` in error case.
240
 * @rst
242
 * @rst
241
 * .. warning:: The returned pointer must be `free(3)`-ed by the caller.
243
 * .. warning:: The returned pointer must be freed by the caller.
242
 * @endrst
244
 * @endrst
243
 */
245
 */
244
char *text_bytes_alloc0(Text*, size_t pos, size_t len);
246
char *text_bytes_alloc0(const Text*, size_t pos, size_t len);
245
/**
247
/**
246
 * @}
248
 * @}
247
 * @defgroup iterator
249
 * @defgroup iterator
248
 * @{
250
 * @{
249
 */
251
 */
250
Iterator text_iterator_get(Text*, size_t pos);
252
Iterator text_iterator_get(const Text*, size_t pos);
253
bool text_iterator_init(const Text*, Iterator*, size_t pos);
254
const Text *text_iterator_text(const Iterator*);
251
bool text_iterator_valid(const Iterator*);
255
bool text_iterator_valid(const Iterator*);
256
bool text_iterator_has_next(const Iterator*);
257
bool text_iterator_has_prev(const Iterator*);
252
bool text_iterator_next(Iterator*);
258
bool text_iterator_next(Iterator*);
253
bool text_iterator_prev(Iterator*);
259
bool text_iterator_prev(Iterator*);
254
/**
260
/**
Lines 256-262 Link Here
256
 * @defgroup iterator_byte
262
 * @defgroup iterator_byte
257
 * @{
263
 * @{
258
 */
264
 */
259
bool text_iterator_byte_get(Iterator*, char *b);
265
bool text_iterator_byte_get(const Iterator*, char *b);
260
bool text_iterator_byte_prev(Iterator*, char *b);
266
bool text_iterator_byte_prev(Iterator*, char *b);
261
bool text_iterator_byte_next(Iterator*, char *b);
267
bool text_iterator_byte_next(Iterator*, char *b);
262
bool text_iterator_byte_find_prev(Iterator*, char b);
268
bool text_iterator_byte_find_prev(Iterator*, char b);
Lines 283-301 Link Here
283
/**
289
/**
284
 * Set a mark.
290
 * Set a mark.
285
 * @rst
291
 * @rst
286
 * .. note:: Setting a mark to `text_size` will always return the current text
292
 * .. note:: Setting a mark to ``text_size`` will always return the
287
 *           size upon lookup.
293
 *           current text size upon lookup.
288
 * @endrst
294
 * @endrst
289
 * @param pos The position at which to store the mark.
295
 * @param pos The position at which to store the mark.
290
 * @return The mark or `EMARK` if an invalid position was given.
296
 * @return The mark or ``EMARK`` if an invalid position was given.
291
 */
297
 */
292
Mark text_mark_set(Text*, size_t pos);
298
Mark text_mark_set(Text*, size_t pos);
293
/**
299
/**
294
 * Lookup a mark.
300
 * Lookup a mark.
295
 * @param mark The mark to look up.
301
 * @param mark The mark to look up.
296
 * @return The byte position or `EPOS` for an invalid mark.
302
 * @return The byte position or ``EPOS`` for an invalid mark.
297
 */
303
 */
298
size_t text_mark_get(Text*, Mark);
304
size_t text_mark_get(const Text*, Mark);
299
/**
305
/**
300
 * @}
306
 * @}
301
 * @defgroup save
307
 * @defgroup save
Lines 308-319 Link Here
308
	/** Automatically chose best option. */
314
	/** Automatically chose best option. */
309
	TEXT_SAVE_AUTO,
315
	TEXT_SAVE_AUTO,
310
	/**
316
	/**
311
	 * Save file atomically using `rename(2)`.
317
	 * Save file atomically using ``rename(2)``.
312
	 *
318
	 *
313
	 * Creates a temporary file, restores all important meta data,
319
	 * Creates a temporary file, restores all important meta data,
314
	 * before moving it atomically to its final (possibly already
320
	 * before moving it atomically to its final (possibly already
315
	 * existing) destination using `rename(2)`. For new files,
321
	 * existing) destination using ``rename(2)``. For new files,
316
	 * permissions are set to `0666 & ~umask`.
322
	 * permissions are set to ``0666 & ~umask``.
317
	 *
323
	 *
318
	 * @rst
324
	 * @rst
319
	 * .. warning:: This approach does not work if:
325
	 * .. warning:: This approach does not work if:
Lines 323-329 Link Here
323
	 *   - File ownership can not be preserved.
329
	 *   - File ownership can not be preserved.
324
	 *   - File group can not be preserved.
330
	 *   - File group can not be preserved.
325
	 *   - Directory permissions do not allow creation of a new file.
331
	 *   - Directory permissions do not allow creation of a new file.
326
	 *   - POSXI ACL can not be preserved (if enabled).
332
	 *   - POSIX ACL can not be preserved (if enabled).
327
	 *   - SELinux security context can not be preserved (if enabled).
333
	 *   - SELinux security context can not be preserved (if enabled).
328
	 * @endrst
334
	 * @endrst
329
	 */
335
	 */
Lines 339-377 Link Here
339
345
340
/**
346
/**
341
 * Save the whole text to the given file name.
347
 * Save the whole text to the given file name.
342
 */
343
bool text_save(Text*, const char *filename);
344
/**
345
 * Save the whole text to the given file name, using the specified method.
346
 *
348
 *
347
 * @rst
349
 * @rst
348
 * .. note:: Equivalent to ``text_save_method(filename, TEXT_SAVE_AUTO)``.
350
 * .. note:: Equivalent to ``text_save_method(filename, TEXT_SAVE_AUTO)``.
349
 * @endrst
351
 * @endrst
350
 */
352
 */
353
bool text_save(Text*, const char *filename);
354
bool text_saveat(Text*, int dirfd, const char *filename);
355
/**
356
 * Save the whole text to the given file name, using the specified method.
357
 */
351
bool text_save_method(Text*, const char *filename, enum TextSaveMethod);
358
bool text_save_method(Text*, const char *filename, enum TextSaveMethod);
359
bool text_saveat_method(Text*, int dirfd, const char *filename, enum TextSaveMethod);
352
360
353
/**
361
/**
354
 * Setup a sequence of write operations.
362
 * Setup a sequence of write operations.
355
 *
363
 *
356
 * The returned `TextSave` pointer can be used to write multiple, possibly
364
 * The returned ``TextSave`` pointer can be used to write multiple, possibly
357
 * non-contigious, file ranges.
365
 * non-contiguous, file ranges.
358
 * @rst
366
 * @rst
359
 * .. warning:: For every call to `text_save_begin` there must be exactly
367
 * .. warning:: For every call to ``text_save_begin`` there must be exactly
360
 *              one matching call to either `text_save_commit` or
368
 *              one matching call to either ``text_save_commit`` or
361
 *              `text_save_cancel` to release the underlying resources.
369
 *              ``text_save_cancel`` to release the underlying resources.
362
 * @endrst
370
 * @endrst
363
 */
371
 */
364
TextSave *text_save_begin(Text*, const char *filename, enum TextSaveMethod);
372
TextSave *text_save_begin(Text*, int dirfd, const char *filename, enum TextSaveMethod);
365
/**
373
/**
366
 * Write file range.
374
 * Write file range.
367
 * @return The number of bytes written or ``-1`` in case of an error.
375
 * @return The number of bytes written or ``-1`` in case of an error.
368
 */
376
 */
369
ssize_t text_save_write_range(TextSave*, Filerange*);
377
ssize_t text_save_write_range(TextSave*, const Filerange*);
370
/**
378
/**
371
 * Commit changes to disk.
379
 * Commit changes to disk.
372
 * @return Whether changes have been saved.
380
 * @return Whether changes have been saved.
373
 * @rst
381
 * @rst
374
 * .. note:: Releases the underlying resources and `free(3)`'s the given `TextSave`
382
 * .. note:: Releases the underlying resources and frees the given ``TextSave``
375
 *           pointer which must no longer be used.
383
 *           pointer which must no longer be used.
376
 * @endrst
384
 * @endrst
377
 */
385
 */
Lines 381-387 Link Here
381
 * @rst
389
 * @rst
382
 * .. note:: Does not guarantee to undo the previous writes (they might have been
390
 * .. note:: Does not guarantee to undo the previous writes (they might have been
383
 *           performed in-place). However, it releases the underlying resources and
391
 *           performed in-place). However, it releases the underlying resources and
384
 *           `free(3)`'s the given `TextSave` pointer which must no longer be used.
392
 *           frees the given ``TextSave`` pointer which must no longer be used.
385
 * @endrst
393
 * @endrst
386
 */
394
 */
387
void text_save_cancel(TextSave*);
395
void text_save_cancel(TextSave*);
Lines 389-400 Link Here
389
 * Write whole text content to file descriptor.
397
 * Write whole text content to file descriptor.
390
 * @return The number of bytes written or ``-1`` in case of an error.
398
 * @return The number of bytes written or ``-1`` in case of an error.
391
 */
399
 */
392
ssize_t text_write(Text*, int fd);
400
ssize_t text_write(const Text*, int fd);
393
/**
401
/**
394
 * Write file range to file descriptor.
402
 * Write file range to file descriptor.
395
 * @return The number of bytes written or ``-1`` in case of an error.
403
 * @return The number of bytes written or ``-1`` in case of an error.
396
 */
404
 */
397
ssize_t text_write_range(Text*, Filerange*, int fd);
405
ssize_t text_write_range(const Text*, const Filerange*, int fd);
398
/**
406
/**
399
 * @}
407
 * @}
400
 * @defgroup misc
408
 * @defgroup misc
Lines 404-410 Link Here
404
 * Check whether ``ptr`` is part of a memory mapped region associated with
412
 * Check whether ``ptr`` is part of a memory mapped region associated with
405
 * this text instance.
413
 * this text instance.
406
 */
414
 */
407
bool text_mmaped(Text*, const char *ptr);
415
bool text_mmaped(const Text*, const char *ptr);
408
/** @} */
416
/** @} */
409
417
410
#endif
418
#endif
(-)vis-0.6/ui.h (-1 / +1 lines)
Lines 7-13 Link Here
7
7
8
/* enable large file optimization for files larger than: */
8
/* enable large file optimization for files larger than: */
9
#define UI_LARGE_FILE_SIZE (1 << 25)
9
#define UI_LARGE_FILE_SIZE (1 << 25)
10
/* enable large file optimization fo files containing lines longer than: */
10
/* enable large file optimization for files containing lines longer than: */
11
#define UI_LARGE_FILE_LINE_SIZE (1 << 16)
11
#define UI_LARGE_FILE_LINE_SIZE (1 << 16)
12
12
13
typedef struct Ui Ui;
13
typedef struct Ui Ui;
(-)vis-0.6/view.c (-3 / +6 lines)
Lines 358-364 Link Here
358
			cell = (Cell){ .data = "\xEF\xBF\xBD", .len = len, .width = 1 };
358
			cell = (Cell){ .data = "\xEF\xBF\xBD", .len = len, .width = 1 };
359
		} else if (len == (size_t)-2) {
359
		} else if (len == (size_t)-2) {
360
			/* not enough bytes available to convert to a
360
			/* not enough bytes available to convert to a
361
			 * wide character. advance file position and read
361
			 * wide character. Advance file position and read
362
			 * another junk into buffer.
362
			 * another junk into buffer.
363
			 */
363
			 */
364
			rem = text_bytes_get(view->text, pos+prev_cell.len, size, text);
364
			rem = text_bytes_get(view->text, pos+prev_cell.len, size, text);
Lines 1196-1203 Link Here
1196
}
1196
}
1197
1197
1198
void view_selections_dispose_all(View *view) {
1198
void view_selections_dispose_all(View *view) {
1199
	for (Selection *s = view->selections, *next; s; s = next) {
1199
	Selection *last = view->selections;
1200
		next = s->next;
1200
	while (last->next)
1201
		last = last->next;
1202
	for (Selection *s = last, *prev; s; s = prev) {
1203
		prev = s->prev;
1201
		if (s != view->selection)
1204
		if (s != view->selection)
1202
			selection_free(s);
1205
			selection_free(s);
1203
	}
1206
	}
(-)vis-0.6/view.h (-11 / +11 lines)
Lines 56-68 Link Here
56
/**
56
/**
57
 * Get window coordinate of text position.
57
 * Get window coordinate of text position.
58
 * @param pos The position to query.
58
 * @param pos The position to query.
59
 * @param line Will be updated with screen line on which `pos` resides.
59
 * @param line Will be updated with screen line on which ``pos`` resides.
60
 * @param row Will be updaded with zero based window row on which `pos` resides.
60
 * @param row Will be updaded with zero based window row on which ``pos`` resides.
61
 * @param col Will be updated with zero based window column which `pos` resides.
61
 * @param col Will be updated with zero based window column on which ``pos`` resides.
62
 * @return Whether `pos` is visible. If not, the pointer arguments are left unmodified.
62
 * @return Whether ``pos`` is visible. If not, the pointer arguments are left unmodified.
63
 */
63
 */
64
bool view_coord_get(View*, size_t pos, Line **line, int *row, int *col);
64
bool view_coord_get(View*, size_t pos, Line **line, int *row, int *col);
65
/** Get position at the start ot the `n`-th window line, counting from 1. */
65
/** Get position at the start of the ``n``-th window line, counting from 1. */
66
size_t view_screenline_goto(View*, int n);
66
size_t view_screenline_goto(View*, int n);
67
/** Get first screen line. */
67
/** Get first screen line. */
68
Line *view_lines_first(View*);
68
Line *view_lines_first(View*);
Lines 122-128 Link Here
122
/**
122
/**
123
 * Dispose an existing selection.
123
 * Dispose an existing selection.
124
 * @rst
124
 * @rst
125
 * .. warning:: Not applicaple for the last existing selection.
125
 * .. warning:: Not applicable for the last existing selection.
126
 * @endrst
126
 * @endrst
127
 */
127
 */
128
bool view_selections_dispose(Selection*);
128
bool view_selections_dispose(Selection*);
Lines 138-144 Link Here
138
 * Query state of primary selection.
138
 * Query state of primary selection.
139
 *
139
 *
140
 * If the primary selection was marked for destruction, return it and
140
 * If the primary selection was marked for destruction, return it and
141
 * clear descruction flag.
141
 * clear destruction flag.
142
 */
142
 */
143
Selection *view_selection_disposed(View*);
143
Selection *view_selection_disposed(View*);
144
/** Dispose all but the primary selection. */
144
/** Dispose all but the primary selection. */
Lines 147-153 Link Here
147
void view_selections_normalize(View*);
147
void view_selections_normalize(View*);
148
/**
148
/**
149
 * Replace currently active selections.
149
 * Replace currently active selections.
150
 * @param array The Array of ``Filerange``s.
150
 * @param array The array of ``Filerange`` objects.
151
 * @param anchored Whether *all* selection should be anchored.
151
 * @param anchored Whether *all* selection should be anchored.
152
 */
152
 */
153
void view_selections_set_all(View*, Array*, bool anchored);
153
void view_selections_set_all(View*, Array*, bool anchored);
Lines 176-182 Link Here
176
/**
176
/**
177
 * Get selection index.
177
 * Get selection index.
178
 * @rst
178
 * @rst
179
 * .. note:: Is always in range `[0, count-1]`.
179
 * .. note:: Is always in range ``[0, count-1]``.
180
 * .. warning: The relative order is determined during creation and assumed
180
 * .. warning: The relative order is determined during creation and assumed
181
 *             to remain the same.
181
 *             to remain the same.
182
 * @endrst
182
 * @endrst
Lines 259-265 Link Here
259
/**
259
/**
260
 * Get zero based index of screen cell on which selection cursor currently resides.
260
 * Get zero based index of screen cell on which selection cursor currently resides.
261
 * @rst
261
 * @rst
262
 * .. warning:: Returns `-1` if the selection cursor is currently not visible.
262
 * .. warning:: Returns ``-1`` if the selection cursor is currently not visible.
263
 * @endrst
263
 * @endrst
264
 */
264
 */
265
int view_cursors_cell_get(Selection*);
265
int view_cursors_cell_get(Selection*);
Lines 324-330 Link Here
324
 */
324
 */
325
/**
325
/**
326
 * Move primary selection cursor to the given position.
326
 * Move primary selection cursor to the given position.
327
 * Makes sure that position is visisble.
327
 * Makes sure that position is visible.
328
 * @rst
328
 * @rst
329
 * .. note:: If position was not visible before, we attempt to show
329
 * .. note:: If position was not visible before, we attempt to show
330
 *           surrounding context. The viewport will be adjusted such
330
 *           surrounding context. The viewport will be adjusted such
(-)vis-0.6/vis-clipboard (-11 / +46 lines)
Lines 8-17 Link Here
8
}
8
}
9
9
10
vc_usage() {
10
vc_usage() {
11
	vc_fatal "`basename $0` [--usable|--copy|--paste]"
11
	vc_fatal "`basename $0` [--selection sel] [--usable|--copy|--paste]"
12
}
12
}
13
13
14
vc_determine_command() {
14
vc_determine_command() {
15
	if [ -n "$WAYLAND_DISPLAY" ]; then
16
		for c in wl-copy wl-paste; do
17
			if type "$c" >/dev/null 2>&1; then
18
				echo "wlclipboard"
19
				return 0
20
			fi
21
		done
22
	fi
23
	
15
	if [ -n "$DISPLAY" ]; then
24
	if [ -n "$DISPLAY" ]; then
16
		for c in xclip xsel; do
25
		for c in xclip xsel; do
17
			if type "$c" >/dev/null 2>&1; then
26
			if type "$c" >/dev/null 2>&1; then
Lines 21-26 Link Here
21
		done
30
		done
22
	fi
31
	fi
23
32
33
	if [ "$sel" = "primary" ]; then
34
		vc_fatal "clipboard primary selection is not supported on your platform"
35
	fi
36
24
	if type pbcopy >/dev/null 2>&1; then
37
	if type pbcopy >/dev/null 2>&1; then
25
		echo 'mac'
38
		echo 'mac'
26
		return 0
39
		return 0
Lines 66-85 Link Here
66
	exit $?
79
	exit $?
67
}
80
}
68
81
82
vc_wlclipboard_copy() {
83
	if [ "$sel" = "primary" ]; then
84
		wl-copy --primary -t TEXT
85
	else
86
		wl-copy -t TEXT
87
	fi
88
}
89
90
vc_wlclipboard_paste() {
91
	if [ "$sel" = "primary" ]; then
92
		wl-paste --primary -t text
93
	else
94
		wl-paste -t text
95
	fi
96
}
97
69
vc_xsel_copy() {
98
vc_xsel_copy() {
70
	xsel -bi
99
	xsel --"$sel" -bi
71
}
100
}
72
101
73
vc_xsel_paste() {
102
vc_xsel_paste() {
74
	xsel -bo
103
	xsel --"$sel" -bo
75
}
104
}
76
105
77
vc_xclip_copy() {
106
vc_xclip_copy() {
78
	xclip -selection clipboard -i >/dev/null 2>&1
107
	xclip -selection "$sel" -i >/dev/null 2>&1
79
}
108
}
80
109
81
vc_xclip_paste() {
110
vc_xclip_paste() {
82
	xclip -selection clipboard -o
111
	xclip -selection "$sel" -o
83
}
112
}
84
113
85
vc_mac_copy() {
114
vc_mac_copy() {
Lines 98-108 Link Here
98
	cat /dev/clipboard
127
	cat /dev/clipboard
99
}
128
}
100
129
101
case "$1" in
130
while [ $# -gt 0 ]; do
102
	--usable) vc_usable;;
131
	case "$1" in
103
	--copy) vc_copy;;
132
		--usable) fn=vc_usable;;
104
	--paste) vc_paste;;
133
		--copy) fn=vc_copy;;
105
	*) ;;
134
		--paste) fn=vc_paste;;
106
esac
135
		--selection) shift; sel="$1";;
136
		*) ;;
137
	esac
138
	shift
139
done
140
141
sel=${sel:-"clipboard"} $fn
107
142
108
vc_usage
143
vc_usage
(-)vis-0.6/vis-cmds.c (-1 / +5 lines)
Lines 361-366 Link Here
361
		windows_arrange(vis, layout);
361
		windows_arrange(vis, layout);
362
		break;
362
		break;
363
	}
363
	}
364
	case OPTION_IGNORECASE:
365
		vis->ignorecase = toggle ? !vis->ignorecase : arg.b;
366
		break;
364
	default:
367
	default:
365
		if (!opt->func)
368
		if (!opt->func)
366
			return false;
369
			return false;
Lines 616-624 Link Here
616
		}
619
		}
617
	}
620
	}
618
621
622
	struct tm tm;
619
	time_t state = text_state(txt);
623
	time_t state = text_state(txt);
620
	char buf[32];
624
	char buf[32];
621
	strftime(buf, sizeof buf, "State from %H:%M", localtime(&state));
625
	strftime(buf, sizeof buf, "State from %H:%M", localtime_r(&state, &tm));
622
	vis_info_show(vis, "%s", buf);
626
	vis_info_show(vis, "%s", buf);
623
627
624
	return pos != EPOS;
628
	return pos != EPOS;
(-)vis-0.6/vis-core.h (-9 / +11 lines)
Lines 14-20 Link Here
14
14
15
/* a mode contains a set of key bindings which are currently valid.
15
/* a mode contains a set of key bindings which are currently valid.
16
 *
16
 *
17
 * each mode can specify one parent mode which is consultated if a given key
17
 * each mode can specify one parent mode which is consulted if a given key
18
 * is not found in the current mode. hence the modes form a tree which is
18
 * is not found in the current mode. hence the modes form a tree which is
19
 * searched from the current mode up towards the root mode until a valid binding
19
 * searched from the current mode up towards the root mode until a valid binding
20
 * is found.
20
 * is found.
Lines 63-75 Link Here
63
};
63
};
64
64
65
typedef struct {
65
typedef struct {
66
	/* operator logic, returns new cursor position, if EPOS is
66
	/* operator logic, returns new cursor position, if EPOS
67
	 * the cursor is disposed (except if it is the primary one) */
67
	 * the cursor is disposed (except if it is the primary one) */
68
	VisOperatorFunction *func;
68
	VisOperatorFunction *func;
69
	void *context;
69
	void *context;
70
} Operator;
70
} Operator;
71
71
72
typedef struct { /* Motion implementation, takes a cursor postion and returns a new one */
72
typedef struct { /* Motion implementation, takes a cursor position and returns a new one */
73
	/* TODO: merge types / use union to save space */
73
	/* TODO: merge types / use union to save space */
74
	size_t (*cur)(Selection*);
74
	size_t (*cur)(Selection*);
75
	size_t (*txt)(Text*, size_t pos);
75
	size_t (*txt)(Text*, size_t pos);
Lines 154-160 Link Here
154
};
154
};
155
155
156
struct Win {
156
struct Win {
157
	Vis *vis;               /* editor instance to which this window belongs to */
157
	Vis *vis;               /* editor instance to which this window belongs */
158
	UiWin *ui;              /* ui object handling visual appearance of this window */
158
	UiWin *ui;              /* ui object handling visual appearance of this window */
159
	File *file;             /* file being displayed in this window */
159
	File *file;             /* file being displayed in this window */
160
	View *view;             /* currently displayed part of underlying text */
160
	View *view;             /* currently displayed part of underlying text */
Lines 167-173 Link Here
167
};
167
};
168
168
169
struct Vis {
169
struct Vis {
170
	Ui *ui;                              /* user interface repsonsible for visual appearance */
170
	Ui *ui;                              /* user interface responsible for visual appearance */
171
	File *files;                         /* all files currently managed by this editor instance */
171
	File *files;                         /* all files currently managed by this editor instance */
172
	File *command_file;                  /* special internal file used to store :-command prompt */
172
	File *command_file;                  /* special internal file used to store :-command prompt */
173
	File *search_file;                   /* special internal file used to store /,? search prompt */
173
	File *search_file;                   /* special internal file used to store /,? search prompt */
Lines 201-226 Link Here
201
	Action action;                       /* current action which is in progress */
201
	Action action;                       /* current action which is in progress */
202
	Action action_prev;                  /* last operator action used by the repeat (dot) command */
202
	Action action_prev;                  /* last operator action used by the repeat (dot) command */
203
	Mode *mode;                          /* currently active mode, used to search for keybindings */
203
	Mode *mode;                          /* currently active mode, used to search for keybindings */
204
	Mode *mode_prev;                     /* previsouly active user mode */
204
	Mode *mode_prev;                     /* previously active user mode */
205
	bool initialized;                    /* whether UI and Lua integration has been initialized */
205
	bool initialized;                    /* whether UI and Lua integration has been initialized */
206
	int nesting_level;                   /* parsing state to hold keep track of { } nesting level */
206
	int nesting_level;                   /* parsing state to hold keep track of { } nesting level */
207
	volatile bool running;               /* exit main loop once this becomes false */
207
	volatile bool running;               /* exit main loop once this becomes false */
208
	int exit_status;                     /* exit status when terminating main loop */
208
	int exit_status;                     /* exit status when terminating main loop */
209
	volatile sig_atomic_t interrupted;   /* abort command (SIGINT occured) */
209
	volatile sig_atomic_t interrupted;   /* abort command (SIGINT occured) */
210
	volatile sig_atomic_t sigbus;        /* one of the memory mapped region became unavailable (SIGBUS) */
210
	volatile sig_atomic_t sigbus;        /* one of the memory mapped regions became unavailable (SIGBUS) */
211
	volatile sig_atomic_t need_resize;   /* need to resize UI (SIGWINCH occured) */
211
	volatile sig_atomic_t need_resize;   /* need to resize UI (SIGWINCH occured) */
212
	volatile sig_atomic_t resume;        /* need to resume UI (SIGCONT occured) */
212
	volatile sig_atomic_t resume;        /* need to resume UI (SIGCONT occured) */
213
	volatile sig_atomic_t terminate;     /* need to terminate we were being killed by SIGTERM */
213
	volatile sig_atomic_t terminate;     /* need to terminate we were being killed by SIGTERM */
214
	sigjmp_buf sigbus_jmpbuf;            /* used to jump back to a known good state in the mainloop after (SIGBUS) */
214
	sigjmp_buf sigbus_jmpbuf;            /* used to jump back to a known good state in the mainloop after (SIGBUS) */
215
	Map *actions;                        /* registered editor actions / special keys commands */
215
	Map *actions;                        /* registered editor actions / special keys commands */
216
	Array actions_user;                  /* dynamically allocated editor actions */
216
	Array actions_user;                  /* dynamically allocated editor actions */
217
	lua_State *lua;                      /* lua context used for syntax highligthing */
217
	lua_State *lua;                      /* lua context used for syntax highlighting */
218
	enum TextLoadMethod load_method;     /* how existing files should be loaded */
218
	enum TextLoadMethod load_method;     /* how existing files should be loaded */
219
	VisEvent *event;
219
	VisEvent *event;
220
	Array operators;
220
	Array operators;
221
	Array motions;
221
	Array motions;
222
	Array textobjects;
222
	Array textobjects;
223
	Array bindings;
223
	Array bindings;
224
	bool ignorecase;                     /* whether to ignore case when searching */
224
};
225
};
225
226
226
enum VisEvents {
227
enum VisEvents {
Lines 235-240 Link Here
235
	VIS_EVENT_WIN_CLOSE,
236
	VIS_EVENT_WIN_CLOSE,
236
	VIS_EVENT_WIN_HIGHLIGHT,
237
	VIS_EVENT_WIN_HIGHLIGHT,
237
	VIS_EVENT_WIN_STATUS,
238
	VIS_EVENT_WIN_STATUS,
239
	VIS_EVENT_TERM_CSI,
238
};
240
};
239
241
240
bool vis_event_emit(Vis*, enum VisEvents, ...);
242
bool vis_event_emit(Vis*, enum VisEvents, ...);
Lines 246-252 Link Here
246
248
247
typedef MarkDef RegisterDef;
249
typedef MarkDef RegisterDef;
248
250
249
/** stuff used by multiple of the vis-* files */
251
/** stuff used by several of the vis-* files */
250
252
251
extern Mode vis_modes[VIS_MODE_INVALID];
253
extern Mode vis_modes[VIS_MODE_INVALID];
252
extern const Movement vis_motions[VIS_MOVE_INVALID];
254
extern const Movement vis_motions[VIS_MOVE_INVALID];
(-)vis-0.6/vis-lua.c (-27 / +109 lines)
Lines 161-166 Link Here
161
void vis_lua_win_close(Vis *vis, Win *win) { }
161
void vis_lua_win_close(Vis *vis, Win *win) { }
162
void vis_lua_win_highlight(Vis *vis, Win *win) { }
162
void vis_lua_win_highlight(Vis *vis, Win *win) { }
163
void vis_lua_win_status(Vis *vis, Win *win) { window_status_update(vis, win); }
163
void vis_lua_win_status(Vis *vis, Win *win) { window_status_update(vis, win); }
164
void vis_lua_term_csi(Vis *vis, const long *csi) { }
164
165
165
#else
166
#else
166
167
Lines 330-336 Link Here
330
	lua_getfield(L, LUA_REGISTRYINDEX, "vis.types");
331
	lua_getfield(L, LUA_REGISTRYINDEX, "vis.types");
331
	lua_getmetatable(L, -2);
332
	lua_getmetatable(L, -2);
332
	lua_gettable(L, -2);
333
	lua_gettable(L, -2);
333
	// XXX: in theory string might become invalid when poped from stack
334
	// XXX: in theory string might become invalid when popped from stack
334
	const char *type = lua_tostring(L, -1);
335
	const char *type = lua_tostring(L, -1);
335
	lua_pop(L, 2);
336
	lua_pop(L, 2);
336
	return type;
337
	return type;
Lines 675-704 Link Here
675
 * @usage
676
 * @usage
676
 * local marks = vis.win.marks
677
 * local marks = vis.win.marks
677
 * for name in vis:mark_names() do
678
 * for name in vis:mark_names() do
678
 *	local mark = marks[name]
679
 * 	local mark = marks[name]
679
 *	for i = 1, #mark do
680
 * 	for i = 1, #mark do
680
 * 		-- do somthing with: name, mark[i].start, mark[i].finish
681
 * 		-- do somthing with: name, mark[i].start, mark[i].finish
681
 *	end
682
 * 	end
682
 * end
683
 * end
683
 */
684
 */
684
static int mark_names_iter(lua_State *L);
685
static int mark_names_iter(lua_State *L);
685
static int mark_names(lua_State *L) {
686
static int mark_names(lua_State *L) {
687
	Vis *vis = obj_ref_check(L, 1, "vis");
688
	lua_pushlightuserdata(L, vis);
686
	enum VisMark *handle = lua_newuserdata(L, sizeof *handle);
689
	enum VisMark *handle = lua_newuserdata(L, sizeof *handle);
687
	*handle = 0;
690
	*handle = 0;
688
	lua_pushcclosure(L, mark_names_iter, 1);
691
	lua_pushcclosure(L, mark_names_iter, 2);
689
	return 1;
692
	return 1;
690
}
693
}
691
694
692
static int mark_names_iter(lua_State *L) {
695
static int mark_names_iter(lua_State *L) {
693
	char mark = '\0';
696
	Vis *vis = lua_touserdata(L, lua_upvalueindex(1));
694
	enum VisMark *handle = lua_touserdata(L, lua_upvalueindex(1));
697
	enum VisMark *handle = lua_touserdata(L, lua_upvalueindex(2));
695
	if (*handle < LENGTH(vis_marks))
698
	char mark = vis_mark_to(vis, *handle);
696
		mark = vis_marks[*handle].name;
697
	else if (VIS_MARK_a <= *handle && *handle <= VIS_MARK_z)
698
		mark = 'a' + *handle - VIS_MARK_a;
699
	if (mark) {
699
	if (mark) {
700
		char name[2] = { mark, '\0' };
700
		lua_pushlstring(L, &mark, 1);
701
		lua_pushstring(L, name);
702
		(*handle)++;
701
		(*handle)++;
703
		return 1;
702
		return 1;
704
	}
703
	}
Lines 719-740 Link Here
719
 */
718
 */
720
static int register_names_iter(lua_State *L);
719
static int register_names_iter(lua_State *L);
721
static int register_names(lua_State *L) {
720
static int register_names(lua_State *L) {
721
	Vis *vis = obj_ref_check(L, 1, "vis");
722
	lua_pushlightuserdata(L, vis);
722
	enum VisRegister *handle = lua_newuserdata(L, sizeof *handle);
723
	enum VisRegister *handle = lua_newuserdata(L, sizeof *handle);
723
	*handle = 0;
724
	*handle = 0;
724
	lua_pushcclosure(L, register_names_iter, 1);
725
	lua_pushcclosure(L, register_names_iter, 2);
725
	return 1;
726
	return 1;
726
}
727
}
727
728
728
static int register_names_iter(lua_State *L) {
729
static int register_names_iter(lua_State *L) {
729
	char reg = '\0';
730
	Vis *vis = lua_touserdata(L, lua_upvalueindex(1));
730
	enum VisRegister *handle = lua_touserdata(L, lua_upvalueindex(1));
731
	enum VisRegister *handle = lua_touserdata(L, lua_upvalueindex(2));
731
	if (*handle < LENGTH(vis_registers))
732
	char reg = vis_register_to(vis, *handle);
732
		reg = vis_registers[*handle].name;
733
	else if (VIS_REG_a <= *handle && *handle <= VIS_REG_z)
734
		reg = 'a' + *handle - VIS_REG_a;
735
	if (reg) {
733
	if (reg) {
736
		char name[2] = { reg, '\0' };
734
		lua_pushlstring(L, &reg, 1);
737
		lua_pushstring(L, name);
738
		(*handle)++;
735
		(*handle)++;
739
		return 1;
736
		return 1;
740
	}
737
	}
Lines 761-767 Link Here
761
 * Display a short message.
758
 * Display a short message.
762
 *
759
 *
763
 * The single line message will be displayed at the bottom of
760
 * The single line message will be displayed at the bottom of
764
 * the scren and automatically hidden once a key is pressed.
761
 * the screen and automatically hidden once a key is pressed.
765
 *
762
 *
766
 * @function info
763
 * @function info
767
 * @tparam string message the message to display
764
 * @tparam string message the message to display
Lines 1312-1318 Link Here
1312
 * eventually hands over control to the editor core. The exit status
1309
 * eventually hands over control to the editor core. The exit status
1313
 * of the most recent call is used.
1310
 * of the most recent call is used.
1314
 *
1311
 *
1315
 * All unsaved chanes will be lost!
1312
 * All unsaved changes will be lost!
1316
 *
1313
 *
1317
 * @function exit
1314
 * @function exit
1318
 * @tparam int code the exit status returned to the operating system
1315
 * @tparam int code the exit status returned to the operating system
Lines 1363-1369 Link Here
1363
 *
1360
 *
1364
 * Will trigger redraw events, make sure to avoid recursive events.
1361
 * Will trigger redraw events, make sure to avoid recursive events.
1365
 *
1362
 *
1366
 * @function draw
1363
 * @function redraw
1367
 */
1364
 */
1368
static int redraw(lua_State *L) {
1365
static int redraw(lua_State *L) {
1369
	Vis *vis = obj_ref_check(L, 1, "vis");
1366
	Vis *vis = obj_ref_check(L, 1, "vis");
Lines 1387-1392 Link Here
1387
 * Currently unconsumed keys in the input queue.
1384
 * Currently unconsumed keys in the input queue.
1388
 * @tfield string input_queue
1385
 * @tfield string input_queue
1389
 */
1386
 */
1387
/***
1388
 * Register name in use.
1389
 * @tfield string register
1390
 */
1391
/***
1392
 * Mark name in use.
1393
 * @tfield string mark
1394
 */
1390
static int vis_index(lua_State *L) {
1395
static int vis_index(lua_State *L) {
1391
	Vis *vis = obj_ref_check(L, 1, "vis");
1396
	Vis *vis = obj_ref_check(L, 1, "vis");
1392
1397
Lines 1424-1434 Link Here
1424
			return 1;
1429
			return 1;
1425
		}
1430
		}
1426
1431
1432
		if (strcmp(key, "register") == 0) {
1433
			char name = vis_register_to(vis, vis_register_used(vis));
1434
			lua_pushlstring(L, &name, 1);
1435
			return 1;
1436
		}
1437
1427
		if (strcmp(key, "registers") == 0) {
1438
		if (strcmp(key, "registers") == 0) {
1428
			obj_ref_new(L, vis->ui, VIS_LUA_TYPE_REGISTERS);
1439
			obj_ref_new(L, vis->ui, VIS_LUA_TYPE_REGISTERS);
1429
			return 1;
1440
			return 1;
1430
		}
1441
		}
1431
1442
1443
		if (strcmp(key, "mark") == 0) {
1444
			char name = vis_mark_to(vis, vis_mark_used(vis));
1445
			lua_pushlstring(L, &name, 1);
1446
			return 1;
1447
		}
1448
1432
		if (strcmp(key, "ui") == 0) {
1449
		if (strcmp(key, "ui") == 0) {
1433
			obj_ref_new(L, vis->ui, VIS_LUA_TYPE_UI);
1450
			obj_ref_new(L, vis->ui, VIS_LUA_TYPE_UI);
1434
			return 1;
1451
			return 1;
Lines 1462-1467 Link Here
1462
			vis_window_focus(obj_ref_check(L, 3, VIS_LUA_TYPE_WINDOW));
1479
			vis_window_focus(obj_ref_check(L, 3, VIS_LUA_TYPE_WINDOW));
1463
			return 0;
1480
			return 0;
1464
		}
1481
		}
1482
1483
		if (strcmp(key, "register") == 0) {
1484
			const char *name = luaL_checkstring(L, 3);
1485
			if (strlen(name) == 1)
1486
				vis_register(vis, vis_register_from(vis, name[0]));
1487
			return 0;
1488
		}
1489
1490
		if (strcmp(key, "mark") == 0) {
1491
			const char *name = luaL_checkstring(L, 3);
1492
			if (strlen(name) == 1)
1493
				vis_mark(vis, vis_mark_from(vis, name[0]));
1494
			return 0;
1495
		}
1465
	}
1496
	}
1466
	return newindex_common(L);
1497
	return newindex_common(L);
1467
}
1498
}
Lines 2066-2071 Link Here
2066
 * File state.
2097
 * File state.
2067
 * @tfield bool modified whether the file contains unsaved changes
2098
 * @tfield bool modified whether the file contains unsaved changes
2068
 */
2099
 */
2100
/***
2101
 * File permission.
2102
 * @tfield int permission the file permission bits as of the most recent load/save
2103
 */
2069
static int file_index(lua_State *L) {
2104
static int file_index(lua_State *L) {
2070
	File *file = obj_ref_check(L, 1, VIS_LUA_TYPE_FILE);
2105
	File *file = obj_ref_check(L, 1, VIS_LUA_TYPE_FILE);
2071
2106
Lines 2095-2105 Link Here
2095
			lua_pushboolean(L, text_modified(file->text));
2130
			lua_pushboolean(L, text_modified(file->text));
2096
			return 1;
2131
			return 1;
2097
		}
2132
		}
2133
2134
		if (strcmp(key, "permission") == 0) {
2135
			struct stat stat = text_stat(file->text);
2136
			lua_pushunsigned(L, stat.st_mode & 0777);
2137
			return 1;
2138
		}
2098
	}
2139
	}
2099
2140
2100
	return index_common(L);
2141
	return index_common(L);
2101
}
2142
}
2102
2143
2144
static int file_newindex(lua_State *L) {
2145
	File *file = obj_ref_check(L, 1, VIS_LUA_TYPE_FILE);
2146
2147
	if (lua_isstring(L, 2)) {
2148
		const char *key = lua_tostring(L, 2);
2149
2150
		if (strcmp(key, "modified") == 0) {
2151
			bool modified = lua_isboolean(L, 3) && lua_toboolean(L, 3);
2152
			if (modified) {
2153
				text_insert(file->text, 0, " ", 1);
2154
				text_delete(file->text, 0, 1);
2155
			} else {
2156
				text_save(file->text, NULL);
2157
			}
2158
			return 0;
2159
		}
2160
	}
2161
2162
	return newindex_common(L);
2163
}
2164
2103
/***
2165
/***
2104
 * Insert data at position.
2166
 * Insert data at position.
2105
 * @function insert
2167
 * @function insert
Lines 2281-2287 Link Here
2281
2343
2282
static const struct luaL_Reg file_funcs[] = {
2344
static const struct luaL_Reg file_funcs[] = {
2283
	{ "__index", file_index },
2345
	{ "__index", file_index },
2284
	{ "__newindex", newindex_common },
2346
	{ "__newindex", file_newindex },
2285
	{ "insert", file_insert },
2347
	{ "insert", file_insert },
2286
	{ "delete", file_delete },
2348
	{ "delete", file_delete },
2287
	{ "lines_iterator", file_lines_iterator },
2349
	{ "lines_iterator", file_lines_iterator },
Lines 2860-2866 Link Here
2860
 * Input key event in either input or replace mode.
2922
 * Input key event in either input or replace mode.
2861
 * @function input
2923
 * @function input
2862
 * @tparam string key
2924
 * @tparam string key
2863
 * @treturn bool whether the key was cosumed or not
2925
 * @treturn bool whether the key was consumed or not
2864
 */
2926
 */
2865
static bool vis_lua_input(Vis *vis, const char *key, size_t len) {
2927
static bool vis_lua_input(Vis *vis, const char *key, size_t len) {
2866
	lua_State *L = vis->lua;
2928
	lua_State *L = vis->lua;
Lines 3050-3055 Link Here
3050
		pcall(vis, L, 1, 0);
3112
		pcall(vis, L, 1, 0);
3051
	} else {
3113
	} else {
3052
		window_status_update(vis, win);
3114
		window_status_update(vis, win);
3115
	}
3116
	lua_pop(L, 1);
3117
}
3118
3119
/***
3120
 * CSI command received from terminal.
3121
 * @function term_csi
3122
 * @param List of CSI parameters
3123
 */
3124
void vis_lua_term_csi(Vis *vis, const long *csi) {
3125
	lua_State *L = vis->lua;
3126
	if (!L)
3127
		return;
3128
	vis_lua_event_get(L, "term_csi");
3129
	if (lua_isfunction(L, -1)) {
3130
		int nargs = csi[1];
3131
		lua_pushinteger(L, csi[0]);
3132
		for (int i = 0; i < nargs; i++)
3133
			lua_pushinteger(L, csi[2 + i]);
3134
		pcall(vis, L, 1 + nargs, 0);
3053
	}
3135
	}
3054
	lua_pop(L, 1);
3136
	lua_pop(L, 1);
3055
}
3137
}
(-)vis-0.6/vis-lua.h (+1 lines)
Lines 37-41 Link Here
37
void vis_lua_win_close(Vis*, Win*);
37
void vis_lua_win_close(Vis*, Win*);
38
void vis_lua_win_highlight(Vis*, Win*);
38
void vis_lua_win_highlight(Vis*, Win*);
39
void vis_lua_win_status(Vis*, Win*);
39
void vis_lua_win_status(Vis*, Win*);
40
void vis_lua_term_csi(Vis*, const long *);
40
41
41
#endif
42
#endif
(-)vis-0.6/vis-marks.c (+10 lines)
Lines 226-231 Link Here
226
	return VIS_MARK_INVALID;
226
	return VIS_MARK_INVALID;
227
}
227
}
228
228
229
char vis_mark_to(Vis *vis, enum VisMark mark) {
230
	if (VIS_MARK_a <= mark && mark <= VIS_MARK_z)
231
		return 'a' + mark - VIS_MARK_a;
232
233
	if (mark < LENGTH(vis_marks))
234
		return vis_marks[mark].name;
235
236
	return '\0';
237
}
238
229
const MarkDef vis_marks[] = {
239
const MarkDef vis_marks[] = {
230
	[VIS_MARK_DEFAULT]        = { '\'', VIS_HELP("Default mark")    },
240
	[VIS_MARK_DEFAULT]        = { '\'', VIS_HELP("Default mark")    },
231
	[VIS_MARK_SELECTION]      = { '^',  VIS_HELP("Last selections") },
241
	[VIS_MARK_SELECTION]      = { '^',  VIS_HELP("Last selections") },
(-)vis-0.6/vis-motions.c (-24 / +82 lines)
Lines 112-119 Link Here
112
	                        VIS_MOVE_LONGWORD_END_NEXT, isspace);
112
	                        VIS_MOVE_LONGWORD_END_NEXT, isspace);
113
}
113
}
114
114
115
static size_t to(Vis *vis, Text *txt, size_t pos) {
115
static size_t to_right(Vis *vis, Text *txt, size_t pos) {
116
	char c;
116
	char c;
117
	size_t hit = text_find_next(txt, pos+1, vis->search_char);
118
	if (!text_byte_get(txt, hit, &c) || c != vis->search_char[0])
119
		return pos;
120
	return hit;
121
}
122
123
static size_t till_right(Vis *vis, Text *txt, size_t pos) {
124
	size_t hit = to_right(vis, txt, pos+1);
125
	if (hit != pos)
126
		return text_char_prev(txt, hit);
127
	return pos;
128
}
129
130
static size_t to_left(Vis *vis, Text *txt, size_t pos) {
131
	return text_find_prev(txt, pos, vis->search_char);
132
}
133
134
static size_t till_left(Vis *vis, Text *txt, size_t pos) {
135
	size_t hit = to_left(vis, txt, pos-1);
136
	if (hit != pos-1)
137
		return text_char_next(txt, hit);
138
	return pos;
139
}
140
141
static size_t to_line_right(Vis *vis, Text *txt, size_t pos) {
142
	char c;
117
	if (pos == text_line_end(txt, pos))
143
	if (pos == text_line_end(txt, pos))
118
		return pos;
144
		return pos;
119
	size_t hit = text_line_find_next(txt, pos+1, vis->search_char);
145
	size_t hit = text_line_find_next(txt, pos+1, vis->search_char);
Lines 122-129 Link Here
122
	return hit;
148
	return hit;
123
}
149
}
124
150
125
static size_t till(Vis *vis, Text *txt, size_t pos) {
151
static size_t till_line_right(Vis *vis, Text *txt, size_t pos) {
126
	size_t hit = to(vis, txt, pos+1);
152
	size_t hit = to_line_right(vis, txt, pos+1);
127
	if (pos == text_line_end(txt, pos))
153
	if (pos == text_line_end(txt, pos))
128
		return pos;
154
		return pos;
129
	if (hit != pos)
155
	if (hit != pos)
Lines 131-144 Link Here
131
	return pos;
157
	return pos;
132
}
158
}
133
159
134
static size_t to_left(Vis *vis, Text *txt, size_t pos) {
160
static size_t to_line_left(Vis *vis, Text *txt, size_t pos) {
135
	return text_line_find_prev(txt, pos, vis->search_char);
161
	return text_line_find_prev(txt, pos, vis->search_char);
136
}
162
}
137
163
138
static size_t till_left(Vis *vis, Text *txt, size_t pos) {
164
static size_t till_line_left(Vis *vis, Text *txt, size_t pos) {
139
	if (pos == text_line_begin(txt, pos))
165
	if (pos == text_line_begin(txt, pos))
140
		return pos;
166
		return pos;
141
	size_t hit = to_left(vis, txt, pos-1);
167
	size_t hit = to_line_left(vis, txt, pos-1);
142
	if (hit != pos-1)
168
	if (hit != pos-1)
143
		return text_char_next(txt, hit);
169
		return text_char_next(txt, hit);
144
	return pos;
170
	return pos;
Lines 294-303 Link Here
294
		}
320
		}
295
		break;
321
		break;
296
	}
322
	}
297
	case VIS_MOVE_RIGHT_TO:
323
	case VIS_MOVE_TO_RIGHT:
298
	case VIS_MOVE_LEFT_TO:
324
	case VIS_MOVE_TO_LEFT:
299
	case VIS_MOVE_RIGHT_TILL:
325
	case VIS_MOVE_TO_LINE_RIGHT:
300
	case VIS_MOVE_LEFT_TILL:
326
	case VIS_MOVE_TO_LINE_LEFT:
327
	case VIS_MOVE_TILL_RIGHT:
328
	case VIS_MOVE_TILL_LEFT:
329
	case VIS_MOVE_TILL_LINE_RIGHT:
330
	case VIS_MOVE_TILL_LINE_LEFT:
301
	{
331
	{
302
		const char *key = va_arg(ap, char*);
332
		const char *key = va_arg(ap, char*);
303
		if (!key)
333
		if (!key)
Lines 314-331 Link Here
314
		break;
344
		break;
315
	case VIS_MOVE_TOTILL_REVERSE:
345
	case VIS_MOVE_TOTILL_REVERSE:
316
		switch (vis->last_totill) {
346
		switch (vis->last_totill) {
317
		case VIS_MOVE_RIGHT_TO:
347
		case VIS_MOVE_TO_RIGHT:
318
			motion = VIS_MOVE_LEFT_TO;
348
			motion = VIS_MOVE_TO_LEFT;
319
			break;
349
			break;
320
		case VIS_MOVE_LEFT_TO:
350
		case VIS_MOVE_TO_LEFT:
321
			motion = VIS_MOVE_RIGHT_TO;
351
			motion = VIS_MOVE_TO_RIGHT;
322
			break;
352
			break;
323
		case VIS_MOVE_RIGHT_TILL:
353
		case VIS_MOVE_TO_LINE_RIGHT:
324
			motion = VIS_MOVE_LEFT_TILL;
354
			motion = VIS_MOVE_TO_LINE_LEFT;
325
			break;
355
			break;
326
		case VIS_MOVE_LEFT_TILL:
356
		case VIS_MOVE_TO_LINE_LEFT:
327
			motion = VIS_MOVE_RIGHT_TILL;
357
			motion = VIS_MOVE_TO_LINE_RIGHT;
328
			break;
358
			break;
359
		case VIS_MOVE_TILL_RIGHT:
360
			motion = VIS_MOVE_TILL_LEFT;
361
			break;
362
		case VIS_MOVE_TILL_LEFT:
363
			motion = VIS_MOVE_TILL_RIGHT;
364
			break;
365
		case VIS_MOVE_TILL_LINE_RIGHT:
366
			motion = VIS_MOVE_TILL_LINE_LEFT;
367
			break;
368
		case VIS_MOVE_TILL_LINE_LEFT:
369
			motion = VIS_MOVE_TILL_LINE_RIGHT;
370
			break;
329
		default:
371
		default:
330
			goto err;
372
			goto err;
331
		}
373
		}
Lines 515-534 Link Here
515
		.txt = lastline,
557
		.txt = lastline,
516
		.type = LINEWISE|LINEWISE_INCLUSIVE|JUMP|IDEMPOTENT,
558
		.type = LINEWISE|LINEWISE_INCLUSIVE|JUMP|IDEMPOTENT,
517
	},
559
	},
518
	[VIS_MOVE_LEFT_TO] = {
560
	[VIS_MOVE_TO_LEFT] = {
519
		.vis = to_left,
561
		.vis = to_left,
520
		.type = COUNT_EXACT,
562
		.type = COUNT_EXACT,
521
	},
563
	},
522
	[VIS_MOVE_RIGHT_TO] = {
564
	[VIS_MOVE_TO_RIGHT] = {
523
		.vis = to,
565
		.vis = to_right,
524
		.type = INCLUSIVE|COUNT_EXACT,
566
		.type = INCLUSIVE|COUNT_EXACT,
525
	},
567
	},
526
	[VIS_MOVE_LEFT_TILL] = {
568
	[VIS_MOVE_TO_LINE_LEFT] = {
569
		.vis = to_line_left,
570
		.type = COUNT_EXACT,
571
	},
572
	[VIS_MOVE_TO_LINE_RIGHT] = {
573
		.vis = to_line_right,
574
		.type = INCLUSIVE|COUNT_EXACT,
575
	},
576
	[VIS_MOVE_TILL_LEFT] = {
527
		.vis = till_left,
577
		.vis = till_left,
528
		.type = COUNT_EXACT,
578
		.type = COUNT_EXACT,
529
	},
579
	},
530
	[VIS_MOVE_RIGHT_TILL] = {
580
	[VIS_MOVE_TILL_RIGHT] = {
531
		.vis = till,
581
		.vis = till_right,
582
		.type = INCLUSIVE|COUNT_EXACT,
583
	},
584
	[VIS_MOVE_TILL_LINE_LEFT] = {
585
		.vis = till_line_left,
586
		.type = COUNT_EXACT,
587
	},
588
	[VIS_MOVE_TILL_LINE_RIGHT] = {
589
		.vis = till_line_right,
532
		.type = INCLUSIVE|COUNT_EXACT,
590
		.type = INCLUSIVE|COUNT_EXACT,
533
	},
591
	},
534
	[VIS_MOVE_SEARCH_WORD_FORWARD] = {
592
	[VIS_MOVE_SEARCH_WORD_FORWARD] = {
(-)vis-0.6/vis-open (-1 / +10 lines)
Lines 8-13 Link Here
8
VIS_MENU_PROMPT=""
8
VIS_MENU_PROMPT=""
9
ALLOW_AUTO_SELECT=1
9
ALLOW_AUTO_SELECT=1
10
10
11
wrap_dirs() {
12
	local o
13
14
	while read o
15
	do
16
		[ -d "$o" ] && printf "%s/\n" "$o" || printf "%s\n" "$o"
17
	done
18
}
19
11
while [ $# -gt 0 ]; do
20
while [ $# -gt 0 ]; do
12
	case "$1" in
21
	case "$1" in
13
	-h|--help)
22
	-h|--help)
Lines 63-69 Link Here
63
72
64
# At this point, we have a bunch of options we need to present to the
73
# At this point, we have a bunch of options we need to present to the
65
# user so they can pick one.
74
# user so they can pick one.
66
CHOICE=$(printf "%s\n" "$@" | vis-menu -b -p "$VIS_MENU_PROMPT")
75
CHOICE=$(printf "%s\n" "$@" | wrap_dirs | vis-menu -b -p "$VIS_MENU_PROMPT")
67
76
68
# Did they pick a file or directory? Who knows, let's let the next iteration figure it out.
77
# Did they pick a file or directory? Who knows, let's let the next iteration figure it out.
69
exec "$0" -p "$VIS_MENU_PROMPT" -- "$CHOICE"
78
exec "$0" -p "$VIS_MENU_PROMPT" -- "$CHOICE"
(-)vis-0.6/vis-prompt.c (-1 / +2 lines)
Lines 63-69 Link Here
63
			pattern = "^:";
63
			pattern = "^:";
64
		else if (prompt->file == vis->search_file)
64
		else if (prompt->file == vis->search_file)
65
			pattern = "^(/|\\?)";
65
			pattern = "^(/|\\?)";
66
		if (pattern && regex && text_regex_compile(regex, pattern, REG_EXTENDED|REG_NEWLINE) == 0) {
66
		int cflags = REG_EXTENDED|REG_NEWLINE|(REG_ICASE*vis->ignorecase);
67
		if (pattern && regex && text_regex_compile(regex, pattern, cflags) == 0) {
67
			size_t end = text_line_end(txt, pos);
68
			size_t end = text_line_end(txt, pos);
68
			size_t prev = text_search_backward(txt, end, regex);
69
			size_t prev = text_search_backward(txt, end, regex);
69
			if (prev > pos)
70
			if (prev > pos)
(-)vis-0.6/vis-registers.c (-9 / +37 lines)
Lines 69-84 Link Here
69
	case REGISTER_CLIPBOARD:
69
	case REGISTER_CLIPBOARD:
70
	{
70
	{
71
		Buffer buferr;
71
		Buffer buferr;
72
		enum VisRegister id = reg - vis->registers;
73
		const char *cmd[] = { VIS_CLIPBOARD, "--paste", "--selection", NULL, NULL };
72
		buffer_init(&buferr);
74
		buffer_init(&buferr);
73
		Buffer *buf = array_get(&reg->values, slot);
75
		Buffer *buf = array_get(&reg->values, slot);
74
		if (!buf)
76
		if (!buf)
75
			return NULL;
77
			return NULL;
76
		buffer_clear(buf);
78
		buffer_clear(buf);
77
79
80
		if (id == VIS_REG_PRIMARY)
81
			cmd[3] = "primary";
82
		else
83
			cmd[3] = "clipboard";
78
		int status = vis_pipe(vis, vis->win->file,
84
		int status = vis_pipe(vis, vis->win->file,
79
			&(Filerange){ .start = 0, .end = 0 },
85
			&(Filerange){ .start = 0, .end = 0 },
80
			(const char*[]){ VIS_CLIPBOARD, "--paste", NULL },
86
			cmd, buf, read_buffer, &buferr, read_buffer);
81
			buf, read_buffer, &buferr, read_buffer);
82
87
83
		if (status != 0)
88
		if (status != 0)
84
			vis_info_show(vis, "Command failed %s", buffer_content0(&buferr));
89
			vis_info_show(vis, "Command failed %s", buffer_content0(&buferr));
Lines 152-162 Link Here
152
	case REGISTER_CLIPBOARD:
157
	case REGISTER_CLIPBOARD:
153
	{
158
	{
154
		Buffer buferr;
159
		Buffer buferr;
160
		const char *cmd[] = { VIS_CLIPBOARD, "--copy", "--selection", NULL, NULL };
161
		enum VisRegister id = reg - vis->registers;
155
		buffer_init(&buferr);
162
		buffer_init(&buferr);
156
163
164
		if (id == VIS_REG_PRIMARY)
165
			cmd[3] = "primary";
166
		else
167
			cmd[3] = "clipboard";
168
157
		int status = vis_pipe(vis, vis->win->file, range,
169
		int status = vis_pipe(vis, vis->win->file, range,
158
			(const char*[]){ VIS_CLIPBOARD, "--copy", NULL },
170
			cmd, NULL, NULL, &buferr, read_buffer);
159
			NULL, NULL, &buferr, read_buffer);
160
171
161
		if (status != 0)
172
		if (status != 0)
162
			vis_info_show(vis, "Command failed %s", buffer_content0(&buferr));
173
			vis_info_show(vis, "Command failed %s", buffer_content0(&buferr));
Lines 186-200 Link Here
186
}
197
}
187
198
188
enum VisRegister vis_register_from(Vis *vis, char reg) {
199
enum VisRegister vis_register_from(Vis *vis, char reg) {
189
	switch (reg) {
190
	case '+': return VIS_REG_CLIPBOARD;
191
	case '@': return VIS_MACRO_LAST_RECORDED;
192
	}
193
200
201
	if (reg == '@')
202
		return VIS_MACRO_LAST_RECORDED;
203
194
	if ('a' <= reg && reg <= 'z')
204
	if ('a' <= reg && reg <= 'z')
195
		return VIS_REG_a + reg - 'a';
205
		return VIS_REG_a + reg - 'a';
196
	if ('A' <= reg && reg <= 'Z')
206
	if ('A' <= reg && reg <= 'Z')
197
		return VIS_REG_A + reg - 'A';
207
		return VIS_REG_A + reg - 'A';
208
198
	for (size_t i = 0; i < LENGTH(vis_registers); i++) {
209
	for (size_t i = 0; i < LENGTH(vis_registers); i++) {
199
		if (vis_registers[i].name == reg)
210
		if (vis_registers[i].name == reg)
200
			return i;
211
			return i;
Lines 202-207 Link Here
202
	return VIS_REG_INVALID;
213
	return VIS_REG_INVALID;
203
}
214
}
204
215
216
char vis_register_to(Vis *vis, enum VisRegister reg) {
217
218
	if (reg == VIS_MACRO_LAST_RECORDED)
219
		return '@';
220
221
	if (VIS_REG_a <= reg && reg <= VIS_REG_z)
222
		return 'a' + reg - VIS_REG_a;
223
	if (VIS_REG_A <= reg && reg <= VIS_REG_Z)
224
		return 'A' + reg - VIS_REG_A;
225
226
	if (reg < LENGTH(vis_registers))
227
		return vis_registers[reg].name;
228
229
	return '\0';
230
}
231
205
void vis_register(Vis *vis, enum VisRegister reg) {
232
void vis_register(Vis *vis, enum VisRegister reg) {
206
	if (VIS_REG_A <= reg && reg <= VIS_REG_Z) {
233
	if (VIS_REG_A <= reg && reg <= VIS_REG_Z) {
207
		vis->action.reg = &vis->registers[VIS_REG_a + reg - VIS_REG_A];
234
		vis->action.reg = &vis->registers[VIS_REG_a + reg - VIS_REG_A];
Lines 275-281 Link Here
275
	[VIS_REG_9]          = { '9', VIS_HELP("9th sub-expression match")                         },
302
	[VIS_REG_9]          = { '9', VIS_HELP("9th sub-expression match")                         },
276
	[VIS_REG_AMPERSAND]  = { '&', VIS_HELP("Last regex match")                                 },
303
	[VIS_REG_AMPERSAND]  = { '&', VIS_HELP("Last regex match")                                 },
277
	[VIS_REG_BLACKHOLE]  = { '_', VIS_HELP("/dev/null register")                               },
304
	[VIS_REG_BLACKHOLE]  = { '_', VIS_HELP("/dev/null register")                               },
278
	[VIS_REG_CLIPBOARD]  = { '*', VIS_HELP("System clipboard register, see vis-clipboard(1)")  },
305
	[VIS_REG_PRIMARY]    = { '*', VIS_HELP("Primary clipboard register, see vis-clipboard(1)") },
306
	[VIS_REG_CLIPBOARD]  = { '+', VIS_HELP("System clipboard register, see vis-clipboard(1)")  },
279
	[VIS_REG_DOT]        = { '.', VIS_HELP("Last inserted text")                               },
307
	[VIS_REG_DOT]        = { '.', VIS_HELP("Last inserted text")                               },
280
	[VIS_REG_SEARCH]     = { '/', VIS_HELP("Last search pattern")                              },
308
	[VIS_REG_SEARCH]     = { '/', VIS_HELP("Last search pattern")                              },
281
	[VIS_REG_COMMAND]    = { ':', VIS_HELP("Last :-command")                                   },
309
	[VIS_REG_COMMAND]    = { ':', VIS_HELP("Last :-command")                                   },
(-)vis-0.6/vis-text-objects.c (-6 lines)
Lines 173-184 Link Here
173
		.txt = object_backtick,
173
		.txt = object_backtick,
174
		.type = TEXTOBJECT_DELIMITED_INNER,
174
		.type = TEXTOBJECT_DELIMITED_INNER,
175
	},
175
	},
176
	[VIS_TEXTOBJECT_OUTER_ENTIRE] = {
177
		.txt = text_object_entire,
178
	},
179
	[VIS_TEXTOBJECT_INNER_ENTIRE] = {
180
		.txt = text_object_entire_inner,
181
        },
182
	[VIS_TEXTOBJECT_OUTER_LINE] = {
176
	[VIS_TEXTOBJECT_OUTER_LINE] = {
183
		.txt = text_object_line,
177
		.txt = text_object_line,
184
	},
178
	},
(-)vis-0.6/vis.c (-6 / +24 lines)
Lines 100-105 Link Here
100
		if (vis->event->quit)
100
		if (vis->event->quit)
101
			vis->event->quit(vis);
101
			vis->event->quit(vis);
102
		break;
102
		break;
103
	case VIS_EVENT_TERM_CSI:
104
		if (vis->event->term_csi)
105
			vis->event->term_csi(vis, va_arg(ap, const long *));
106
		break;
103
	}
107
	}
104
108
105
	va_end(ap);
109
	va_end(ap);
Lines 675-680 Link Here
675
		register_init(&vis->registers[i]);
679
		register_init(&vis->registers[i]);
676
	vis->registers[VIS_REG_BLACKHOLE].type = REGISTER_BLACKHOLE;
680
	vis->registers[VIS_REG_BLACKHOLE].type = REGISTER_BLACKHOLE;
677
	vis->registers[VIS_REG_CLIPBOARD].type = REGISTER_CLIPBOARD;
681
	vis->registers[VIS_REG_CLIPBOARD].type = REGISTER_CLIPBOARD;
682
	vis->registers[VIS_REG_PRIMARY].type = REGISTER_CLIPBOARD;
678
	vis->registers[VIS_REG_NUMBER].type = REGISTER_NUMBER;
683
	vis->registers[VIS_REG_NUMBER].type = REGISTER_NUMBER;
679
	array_init(&vis->operators);
684
	array_init(&vis->operators);
680
	array_init(&vis->motions);
685
	array_init(&vis->motions);
Lines 1013-1019 Link Here
1013
			register_resize(reg, last_reg_slot+1);
1018
			register_resize(reg, last_reg_slot+1);
1014
		}
1019
		}
1015
1020
1016
		/* we do not support visual repeat, still do something resonable */
1021
		/* we do not support visual repeat, still do something reasonable */
1017
		if (vis->mode->visual && !a->movement && !a->textobj)
1022
		if (vis->mode->visual && !a->movement && !a->textobj)
1018
			a->movement = &vis_motions[VIS_MOVE_NOP];
1023
			a->movement = &vis_motions[VIS_MOVE_NOP];
1019
1024
Lines 1303-1308 Link Here
1303
	}
1308
	}
1304
1309
1305
	TermKey *termkey = vis->ui->termkey_get(vis->ui);
1310
	TermKey *termkey = vis->ui->termkey_get(vis->ui);
1311
	if (key.type == TERMKEY_TYPE_UNKNOWN_CSI) {
1312
		long args[18];
1313
		size_t nargs;
1314
		unsigned long cmd;
1315
		if (termkey_interpret_csi(termkey, &key, &args[2], &nargs, &cmd) == TERMKEY_RES_KEY) {
1316
			args[0] = (long)cmd;
1317
			args[1] = nargs;
1318
			vis_event_emit(vis, VIS_EVENT_TERM_CSI, args);
1319
		}
1320
		return getkey(vis);
1321
	}
1306
	termkey_strfkey(termkey, vis->key, sizeof(vis->key), &key, TERMKEY_FORMAT_VIM);
1322
	termkey_strfkey(termkey, vis->key, sizeof(vis->key), &key, TERMKEY_FORMAT_VIM);
1307
	return vis->key;
1323
	return vis->key;
1308
}
1324
}
Lines 1380-1386 Link Here
1380
			vis_die(vis, "Killed by SIGTERM\n");
1396
			vis_die(vis, "Killed by SIGTERM\n");
1381
		if (vis->interrupted) {
1397
		if (vis->interrupted) {
1382
			vis->interrupted = false;
1398
			vis->interrupted = false;
1383
			vis_keys_feed(vis, "<C-c>");
1399
			vis_keys_push(vis, "<C-c>", 0, true);
1400
			continue;
1384
		}
1401
		}
1385
1402
1386
		if (vis->resume) {
1403
		if (vis->resume) {
Lines 1669-1675 Link Here
1669
		size_t newpos = vis_text_insert_nl(vis, txt, pos);
1686
		size_t newpos = vis_text_insert_nl(vis, txt, pos);
1670
		/* This is a bit of a hack to fix cursor positioning when
1687
		/* This is a bit of a hack to fix cursor positioning when
1671
		 * inserting a new line at the start of the view port.
1688
		 * inserting a new line at the start of the view port.
1672
		 * It has the effect of reseting the mark used by the view
1689
		 * It has the effect of resetting the mark used by the view
1673
		 * code to keep track of the start of the visible region.
1690
		 * code to keep track of the start of the visible region.
1674
		 */
1691
		 */
1675
		view_cursors_to(s, pos);
1692
		view_cursors_to(s, pos);
Lines 1684-1690 Link Here
1684
	Regex *regex = text_regex_new();
1701
	Regex *regex = text_regex_new();
1685
	if (!regex)
1702
	if (!regex)
1686
		return NULL;
1703
		return NULL;
1687
	if (text_regex_compile(regex, pattern, REG_EXTENDED|REG_NEWLINE) != 0) {
1704
	int cflags = REG_EXTENDED|REG_NEWLINE|(REG_ICASE*vis->ignorecase);
1705
	if (text_regex_compile(regex, pattern, cflags) != 0) {
1688
		text_regex_free(regex);
1706
		text_regex_free(regex);
1689
		return NULL;
1707
		return NULL;
1690
	}
1708
	}
Lines 1842-1849 Link Here
1842
			if (len > 0) {
1860
			if (len > 0) {
1843
				rout.start += len;
1861
				rout.start += len;
1844
				if (text_range_size(&rout) == 0) {
1862
				if (text_range_size(&rout) == 0) {
1845
					close(pout[1]);
1863
					close(pin[1]);
1846
					pout[1] = -1;
1864
					pin[1] = -1;
1847
				}
1865
				}
1848
			} else {
1866
			} else {
1849
				close(pin[1]);
1867
				close(pin[1]);
(-)vis-0.6/vis.h (-17 / +23 lines)
Lines 57-62 Link Here
57
	void (*win_close)(Vis*, Win*);
57
	void (*win_close)(Vis*, Win*);
58
	void (*win_highlight)(Vis*, Win*);
58
	void (*win_highlight)(Vis*, Win*);
59
	void (*win_status)(Vis*, Win*);
59
	void (*win_status)(Vis*, Win*);
60
	void (*term_csi)(Vis*, const long *);
60
} VisEvent;
61
} VisEvent;
61
62
62
/** Union used to pass arguments to key action functions. */
63
/** Union used to pass arguments to key action functions. */
Lines 76-82 Link Here
76
 * @rst
77
 * @rst
77
 * .. note:: An empty string ``""`` indicates that no further input is available.
78
 * .. note:: An empty string ``""`` indicates that no further input is available.
78
 * @endrst
79
 * @endrst
79
 * @return Pointer to first non-cosumed key.
80
 * @return Pointer to first non-consumed key.
80
 * @rst
81
 * @rst
81
 * .. warning:: Must be in range ``[keys, keys+strlen(keys)]`` or ``NULL`` to
82
 * .. warning:: Must be in range ``[keys, keys+strlen(keys)]`` or ``NULL`` to
82
 *              indicate that not enough input was available. In the latter case
83
 *              indicate that not enough input was available. In the latter case
Lines 130-136 Link Here
130
void vis_die(Vis*, const char *msg, ...) __attribute__((noreturn,format(printf, 2, 3)));
131
void vis_die(Vis*, const char *msg, ...) __attribute__((noreturn,format(printf, 2, 3)));
131
132
132
/**
133
/**
133
 * Temporarily supsend the editor process.
134
 * Temporarily suspend the editor process.
134
 * @rst
135
 * @rst
135
 * .. note:: This function will generate a ``SIGTSTP`` signal.
136
 * .. note:: This function will generate a ``SIGTSTP`` signal.
136
 * @endrst
137
 * @endrst
Lines 221-229 Link Here
221
void vis_window_focus(Win*);
222
void vis_window_focus(Win*);
222
/** Swap location of two windows. */
223
/** Swap location of two windows. */
223
void vis_window_swap(Win*, Win*);
224
void vis_window_swap(Win*, Win*);
224
/** Query window dimension. */
225
/** Query window width. */
225
int vis_window_width_get(const Win*);
226
int vis_window_width_get(const Win*);
226
/** Query window dimension. */
227
/** Query window height. */
227
int vis_window_height_get(const Win*);
228
int vis_window_height_get(const Win*);
228
/**
229
/**
229
 * @}
230
 * @}
Lines 263-269 Link Here
263
/** Perform insertion at all cursor positions. */
264
/** Perform insertion at all cursor positions. */
264
void vis_insert_key(Vis*, const char *data, size_t len);
265
void vis_insert_key(Vis*, const char *data, size_t len);
265
/**
266
/**
266
 * Perform character subsitution at all cursor positions.
267
 * Perform character substitution at all cursor positions.
267
 * @rst
268
 * @rst
268
 * .. note:: Does not replace new line characters.
269
 * .. note:: Does not replace new line characters.
269
 * @endrst
270
 * @endrst
Lines 432-438 Link Here
432
 *
433
 *
433
 *  - `VIS_OP_JOIN`       a char pointer referring to the text to insert between lines.
434
 *  - `VIS_OP_JOIN`       a char pointer referring to the text to insert between lines.
434
 *  - `VIS_OP_MODESWITCH` an ``enum VisMode`` indicating the mode to switch to.
435
 *  - `VIS_OP_MODESWITCH` an ``enum VisMode`` indicating the mode to switch to.
435
 *  - `VIS_OP_REPLACE`    a char pointer reffering to the replacement character.
436
 *  - `VIS_OP_REPLACE`    a char pointer referring to the replacement character.
436
 */
437
 */
437
bool vis_operator(Vis*, enum VisOperator, ...);
438
bool vis_operator(Vis*, enum VisOperator, ...);
438
439
Lines 490-499 Link Here
490
	VIS_MOVE_PARENTHESIS_START,
491
	VIS_MOVE_PARENTHESIS_START,
491
	VIS_MOVE_PARENTHESIS_END,
492
	VIS_MOVE_PARENTHESIS_END,
492
	VIS_MOVE_BRACKET_MATCH,
493
	VIS_MOVE_BRACKET_MATCH,
493
	VIS_MOVE_LEFT_TO,
494
	VIS_MOVE_TO_LEFT,
494
	VIS_MOVE_RIGHT_TO,
495
	VIS_MOVE_TO_RIGHT,
495
	VIS_MOVE_LEFT_TILL,
496
	VIS_MOVE_TO_LINE_LEFT,
496
	VIS_MOVE_RIGHT_TILL,
497
	VIS_MOVE_TO_LINE_RIGHT,
498
	VIS_MOVE_TILL_LEFT,
499
	VIS_MOVE_TILL_RIGHT,
500
	VIS_MOVE_TILL_LINE_LEFT,
501
	VIS_MOVE_TILL_LINE_RIGHT,
497
	VIS_MOVE_FILE_BEGIN,
502
	VIS_MOVE_FILE_BEGIN,
498
	VIS_MOVE_FILE_END,
503
	VIS_MOVE_FILE_END,
499
	VIS_MOVE_SEARCH_WORD_FORWARD,
504
	VIS_MOVE_SEARCH_WORD_FORWARD,
Lines 622-629 Link Here
622
	VIS_TEXTOBJECT_INNER_SINGLE_QUOTE,
627
	VIS_TEXTOBJECT_INNER_SINGLE_QUOTE,
623
	VIS_TEXTOBJECT_OUTER_BACKTICK,
628
	VIS_TEXTOBJECT_OUTER_BACKTICK,
624
	VIS_TEXTOBJECT_INNER_BACKTICK,
629
	VIS_TEXTOBJECT_INNER_BACKTICK,
625
	VIS_TEXTOBJECT_OUTER_ENTIRE,
626
	VIS_TEXTOBJECT_INNER_ENTIRE,
627
	VIS_TEXTOBJECT_OUTER_LINE,
630
	VIS_TEXTOBJECT_OUTER_LINE,
628
	VIS_TEXTOBJECT_INNER_LINE,
631
	VIS_TEXTOBJECT_INNER_LINE,
629
	VIS_TEXTOBJECT_INDENTATION,
632
	VIS_TEXTOBJECT_INDENTATION,
Lines 675-682 Link Here
675
 * @defgroup vis_marks
678
 * @defgroup vis_marks
676
 * @{
679
 * @{
677
 */
680
 */
678
/** Translate single character mark name to corresponding constant. */
681
/** Translate between single character mark name and corresponding constant. */
679
enum VisMark vis_mark_from(Vis*, char mark);
682
enum VisMark vis_mark_from(Vis*, char mark);
683
char vis_mark_to(Vis*, enum VisMark);
680
/**
684
/**
681
 * Specify mark to use.
685
 * Specify mark to use.
682
 * @rst
686
 * @rst
Lines 731-736 Link Here
731
	VIS_REG_9,
735
	VIS_REG_9,
732
	VIS_REG_BLACKHOLE,  /* /dev/null register */
736
	VIS_REG_BLACKHOLE,  /* /dev/null register */
733
	VIS_REG_CLIPBOARD,  /* system clipboard register */
737
	VIS_REG_CLIPBOARD,  /* system clipboard register */
738
	VIS_REG_PRIMARY,    /* system primary clipboard register */
734
	VIS_REG_DOT,        /* last inserted text, copy of VIS_MACRO_OPERATOR */
739
	VIS_REG_DOT,        /* last inserted text, copy of VIS_MACRO_OPERATOR */
735
	VIS_REG_SEARCH,     /* last used search pattern "/ */
740
	VIS_REG_SEARCH,     /* last used search pattern "/ */
736
	VIS_REG_COMMAND,    /* last used :-command ": */
741
	VIS_REG_COMMAND,    /* last used :-command ": */
Lines 758-765 Link Here
758
 * @defgroup vis_registers
763
 * @defgroup vis_registers
759
 * @{
764
 * @{
760
 */
765
 */
761
/** Translate single character register name to corresponding constant. */
766
/** Translate between single character register name and corresponding constant. */
762
enum VisRegister vis_register_from(Vis*, char reg);
767
enum VisRegister vis_register_from(Vis*, char reg);
768
char vis_register_to(Vis*, enum VisRegister);
763
/**
769
/**
764
 * Specify register to use.
770
 * Specify register to use.
765
 * @rst
771
 * @rst
Lines 772-778 Link Here
772
 * Get register content.
778
 * Get register content.
773
 * @return An array of ``TextString`` structs.
779
 * @return An array of ``TextString`` structs.
774
 * @rst
780
 * @rst
775
 * .. warning:: The caller must eventually free the array ressources using
781
 * .. warning:: The caller must eventually free the array resources using
776
 *              ``array_release``.
782
 *              ``array_release``.
777
 * @endrst
783
 * @endrst
778
 */
784
 */
Lines 851-857 Link Here
851
 * Option handler function.
857
 * Option handler function.
852
 * @param win The window to which option should apply, might be ``NULL``.
858
 * @param win The window to which option should apply, might be ``NULL``.
853
 * @param context User provided context pointer as given to `vis_option_register`.
859
 * @param context User provided context pointer as given to `vis_option_register`.
854
 * @param force Whether the option was specfied with a bang ``!``.
860
 * @param force Whether the option was specified with a bang ``!``.
855
 * @param name Name of option which was set.
861
 * @param name Name of option which was set.
856
 * @param arg The new option value.
862
 * @param arg The new option value.
857
 */
863
 */
Lines 962-968 Link Here
962
Regex *vis_regex(Vis*, const char *pattern);
968
Regex *vis_regex(Vis*, const char *pattern);
963
969
964
/**
970
/**
965
 * Take an undo snaphost to which we can later revert to.
971
 * Take an undo snapshot to which we can later revert.
966
 * @rst
972
 * @rst
967
 * .. note:: Does nothing when invoked while replaying a macro.
973
 * .. note:: Does nothing when invoked while replaying a macro.
968
 * @endrst
974
 * @endrst

Return to bug 46325