GithubHelp home page GithubHelp logo

martanne / vis Goto Github PK

View Code? Open in Web Editor NEW
4.2K 103.0 257.0 5.78 MB

A vi-like editor based on Plan 9's structural regular expressions

License: Other

Makefile 0.96% C 53.46% Shell 0.66% Lua 44.19% Dockerfile 0.06% Roff 0.61% Batchfile 0.06%
text-editor structural-regex modal-editing console-application c lua

vis's Introduction

Vis - Combining Modal Editing with Structural Regular Expressions

builds.sr.ht status Coverity Scan Build Status codecov Documentation Status #vis-editor on libera

Vis aims to be a modern, legacy-free, simple yet efficient editor, combining the strengths of both vi(m) and sam.

It extends vi's modal editing with built-in support for multiple cursors/selections and combines it with sam's structural regular expression based command language.

A universal editor, it has decent Unicode support and should cope with arbitrary files, including large, binary or single-line ones.

Efficient syntax highlighting is provided using Parsing Expression Grammars, which can be conveniently expressed using Lua in the form of LPeg.

The editor core is written in a reasonable amount of clean (your mileage may vary), modern and legacy-free C code, enabling it to run in resource-constrained environments. The implementation should be easy to hack on and encourages experimentation. There is also a Lua API for in-process extensions.

Vis strives to be simple and focuses on its core task: efficient text management. Clipboard and digraph handling as well as a fuzzy file open dialog are all provided by independent utilities. There exist plans to use a client/server architecture, delegating window management to your windowing system or favorite terminal multiplexer.

The intention is not to be bug-for-bug compatible with vi(m). Instead,
we aim to provide more powerful editing features based on an elegant design and clean implementation.

vis demo

Build instructions

In order to build vis you will need a C99 compiler, a POSIX.1-2008 compatible environment as well as:

  • libtermkey
  • curses (recommended)
  • Lua >= 5.2 (optional)
  • LPeg >= 0.12 (optional runtime dependency required for syntax highlighting)
  • TRE (optional for more memory efficient regex search)

Assuming these dependencies are met, execute:

$ ./configure && make && sudo make install

By default the configure script will try to auto detect support for Lua using pkg-config(1). See configure --help for a list of supported options. You can also manually tweak the generated config.mk file.

Or simply use one of the distribution provided packages.

Documentation

End user documentation can be found in the vis(1) manual page and the Wiki. Read the FAQ for common questions. Learn about some differences compared to sam(1) and vim(1), respectively.

C API as well as Lua API documentation is also available.

Non Goals

Some features which will not be implemented:

  • tabs / multiple workspaces / advanced window management
  • file and directory browser
  • support for file archives (tar, zip, ...)
  • support for network protocols (ftp, http, ssh ...)
  • encryption
  • compression
  • GUIs (neither x11, motif, gtk, win32 ...) although the codebase should make it easy to add them
  • VimL
  • right-to-left text
  • ex mode, we have more elegant structural regexp
  • diff mode
  • vimgrep
  • internal spell checker
  • lots of compile time configurable features / #ifdef mess

How to help?

There are plenty of ways to contribute, below are a few ideas:

Checkout the Developer Overview to get started and do not hesitate to ask question in the #vis-editor IRC channel on libera (join via your browser).

vis's People

Contributors

deepcube avatar dther avatar erf avatar eworm-de avatar fischerling avatar ii8 avatar jeremybobbin avatar jvoisin avatar kdsch avatar lanodan avatar larryhynes avatar martanne avatar matzeb avatar mcepl avatar michaelforney avatar nomarian avatar rgburke avatar rnpnr avatar s-gilles avatar screwtapello avatar shugyousha avatar silasdb avatar singpolyma avatar tiedyeddevil avatar tosch42 avatar two-finger avatar tycho avatar x1ddos avatar xomachine avatar zsugabubus avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

vis's Issues

LPeg based syntax highlighting & Lua integration

During the last couple of weeks I've been investigating a new mechanism to implement syntax highlighting. So far the best solution seems to be based on LPeg.

Advantages:

  • the Scintillua project has already written lexers for ~90 programming languages which can be reused as is. Improvements can be shared, no need to start from scratch and reinvent the wheel.
  • Parsing Expression Grammars (PEG) are
    strictly more powerful than regular expressions and can thus handle certain constructs which weren't possible before
  • PEG are closed under composition i.e. they can be easily combined e.g. a HTML lexer can reference the grammars for JavaScript and CSS
  • flexible rule / themes definition by means of a lightweight programming language: Lua

Disadvantages:

  • currently no lexers for APL and ledger formats which are supported by the old C/regex based approach. APL in particular is used by one of the most active user/contributor (@TieDyedDevil).
  • more dependencies: Lua and LPeg. A self-contained statically linked binary against musl libc, ncurses (including built-in terminfo entries), libtermkey, lua and lpeg as produced by make standalone is about ~600K large. I still consider that acceptable. I have no prior experience with Lua, but from what I've seen so far it seems to share a quite a few properties with vis, namely to be: simple, small and efficient.

The current state can be found in the lua branch. There are likely still some problems, in particular nested lexers are not handled properly.

If we decide to go that route then there is the question which role Lua should play within vis. Should it just be an optional component enabling syntax highlighting? Or should it be tightly integrated and provide a sort of "plug-in" API? Embedding vs extending? In the extreme case, should vis be a lua script calling into an efficient C-based text manipulation library?

Comments?

No tags

โค๏ธ โค๏ธ โค๏ธ Please create a tag some time, much appreciated! โค๏ธ โค๏ธ โค๏ธ

:help command causes segfault

This may be specific to GNU libc. Invoking :help causes a segfault.

The text_vprintf() function reuses its ap argument. My best guess is that the first call to vsnprintf() moves ap while the second call expects it to have remained the same.

This patch resolves the issue for me:

diff --git a/text.c b/text.c
index 94a32f9..5e531ab 100644
--- a/text.c
+++ b/text.c
@@ -643,11 +643,13 @@ bool text_printf(Text *txt, size_t pos, const char *format, ...) {
 }

 bool text_vprintf(Text *txt, size_t pos, const char *format, va_list ap) {
+   va_list ap_save;
+   va_copy(ap_save, ap);
    int len = vsnprintf(NULL, 0, format, ap);
    if (len == -1)
        return false;
    char *buf = malloc(len+1);
-   bool ret = buf && (vsnprintf(buf, len+1, format, ap) == len) && text_insert(txt, pos, buf, len);
+   bool ret = buf && (vsnprintf(buf, len+1, format, ap_save) == len) && text_insert(txt, pos, buf, len);
    free(buf);
    return ret;
 }

overwriting symlinks issue

It seems like vis does not follow soft links? If you open a link with vis and save it, it'll overwrite the link.

touch file
ln -s file link
vis link
:wq

Buffer overflow with `!ls`

This is was I get with !ls

:!ls*** buffer overflow detected ***: vis terminated
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x78c4e)[0x7f8a2229bc4e]
/lib/x86_64-linux-gnu/libc.so.6(__fortify_fail+0x5c)[0x7f8a2233be8c]
/lib/x86_64-linux-gnu/libc.so.6(+0x116e80)[0x7f8a22339e80]
/lib/x86_64-linux-gnu/libc.so.6(+0x118dd7)[0x7f8a2233bdd7]
vis(+0x1438e)[0x7f8a2282738e]
vis(+0x13e52)[0x7f8a22826e52]
vis(+0x16de7)[0x7f8a22829de7]
vis(+0x16e5d)[0x7f8a22829e5d]
vis(+0x15c61)[0x7f8a22828c61]
vis(+0x15e63)[0x7f8a22828e63]
vis(+0x810e)[0x7f8a2281b10e]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f8a22243a40]
vis(+0x81a9)[0x7f8a2281b1a9]
======= Memory map: ========
7f8a216e1000-7f8a216f7000 r-xp 00000000 fc:01 1835079                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7f8a216f7000-7f8a218f6000 ---p 00016000 fc:01 1835079                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7f8a218f6000-7f8a218f7000 rw-p 00015000 fc:01 1835079                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7f8a218f7000-7f8a21bc1000 r--p 00000000 fc:01 5506843                    /usr/lib/locale/locale-archive
7f8a21bc1000-7f8a21bc4000 r-xp 00000000 fc:01 1835187                    /lib/x86_64-linux-gnu/libdl-2.21.so
7f8a21bc4000-7f8a21dc3000 ---p 00003000 fc:01 1835187                    /lib/x86_64-linux-gnu/libdl-2.21.so
7f8a21dc3000-7f8a21dc4000 r--p 00002000 fc:01 1835187                    /lib/x86_64-linux-gnu/libdl-2.21.so
7f8a21dc4000-7f8a21dc5000 rw-p 00003000 fc:01 1835187                    /lib/x86_64-linux-gnu/libdl-2.21.so
7f8a21dc5000-7f8a21dea000 r-xp 00000000 fc:01 1835190                    /lib/x86_64-linux-gnu/libtinfo.so.5.9
7f8a21dea000-7f8a21fe9000 ---p 00025000 fc:01 1835190                    /lib/x86_64-linux-gnu/libtinfo.so.5.9
7f8a21fe9000-7f8a21fed000 r--p 00024000 fc:01 1835190                    /lib/x86_64-linux-gnu/libtinfo.so.5.9
7f8a21fed000-7f8a21fee000 rw-p 00028000 fc:01 1835190                    /lib/x86_64-linux-gnu/libtinfo.so.5.9
7f8a21fee000-7f8a22021000 r-xp 00000000 fc:01 1835196                    /lib/x86_64-linux-gnu/libncursesw.so.5.9
7f8a22021000-7f8a22221000 ---p 00033000 fc:01 1835196                    /lib/x86_64-linux-gnu/libncursesw.so.5.9
7f8a22221000-7f8a22222000 r--p 00033000 fc:01 1835196                    /lib/x86_64-linux-gnu/libncursesw.so.5.9
7f8a22222000-7f8a22223000 rw-p 00034000 fc:01 1835196                    /lib/x86_64-linux-gnu/libncursesw.so.5.9
7f8a22223000-7f8a223e3000 r-xp 00000000 fc:01 1835405                    /lib/x86_64-linux-gnu/libc-2.21.so
7f8a223e3000-7f8a225e3000 ---p 001c0000 fc:01 1835405                    /lib/x86_64-linux-gnu/libc-2.21.so
7f8a225e3000-7f8a225e7000 r--p 001c0000 fc:01 1835405                    /lib/x86_64-linux-gnu/libc-2.21.so
7f8a225e7000-7f8a225e9000 rw-p 001c4000 fc:01 1835405                    /lib/x86_64-linux-gnu/libc-2.21.so
7f8a225e9000-7f8a225ed000 rw-p 00000000 00:00 0 
7f8a225ed000-7f8a22611000 r-xp 00000000 fc:01 1835265                    /lib/x86_64-linux-gnu/ld-2.21.so
7f8a22810000-7f8a22811000 r--p 00023000 fc:01 1835265                    /lib/x86_64-linux-gnu/ld-2.21.so
7f8a22811000-7f8a22812000 rw-p 00024000 fc:01 1835265                    /lib/x86_64-linux-gnu/ld-2.21.so
7f8a22812000-7f8a22813000 rw-p 00000000 00:00 0 
7f8a22813000-7f8a22831000 r-xp 00000000 fc:01 5507050                    /usr/local/bin/vis
7f8a22864000-7f8a229ff000 rw-p 00000000 00:00 0 
7f8a229ff000-7f8a22a06000 r--s 00000000 fc:01 5645165                    /usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache
7f8a22a06000-7f8a22a0a000 rw-p 00000000 00:00 0 
7f8a22a0d000-7f8a22a31000 rw-p 00000000 00:00 0 
7f8a22a31000-7f8a22a32000 r--p 0001e000 fc:01 5507050                    /usr/local/bin/vis
7f8a22a32000-7f8a22a40000 rw-p 0001f000 fc:01 5507050                    /usr/local/bin/vis
7f8a24813000-7f8a24d31000 rw-p 00000000 00:00 0                          [heap]
7ffd2c432000-7ffd2c453000 rw-p 00000000 00:00 0                          [stack]
7ffd2c4d9000-7ffd2c4db000 r--p 00000000 00:00 0                          [vvar]
7ffd2c4db000-7ffd2c4dd000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
zsh: abort (core dumped)  vis
jvoisin@kaa 20:10 ~ 

Same with ! alone. I can't reproduce with the debug version, sorry :/

Building on OS X

For future reference, in order to build this on OS X I had to make some small alterations. Here's the diff:

diff --git i/config.mk w/config.mk
index 06b69fa..d434a2b 100644
--- i/config.mk
+++ w/config.mk
@@ -7,7 +7,7 @@ PREFIX = /usr/local
 MANPREFIX = ${PREFIX}/share/man

 INCS = -I.
-LIBS = -lc -lncursesw
+LIBS = -lc -lncurses

 CFLAGS += -std=c99 -Os ${INCS} -DVERSION=\"${VERSION}\" -DNDEBUG -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700

diff --git i/vis.c w/vis.c
index 696d0f2..451a60a 100644
--- i/vis.c
+++ w/vis.c
@@ -33,6 +33,8 @@
 #include "text-objects.h"
 #include "util.h"

+#define SIGWINCH 100
+
 #ifdef PDCURSES
 int ESCDELAY;
 #endif

SIGWINCH didn't exist so I just defined it as something random. Also I had to compile with ncurses instead of ncursesw since the latter was not found.

handle ^w^j as well as ^w+j (faster typing)

        { { CONTROL('w'), NONE('j') }, call,           { .f = editor_window_next   } },
        { { CONTROL('w'), NONE('k') }, call,           { .f = editor_window_prev   } },
        { { CONTROL('w'), CONTROL('j') }, call,        { .f = editor_window_next   } },
        { { CONTROL('w'), CONTROL('k') }, call,        { .f = editor_window_prev   } },

editor.c - use after free

editor_window_close(win) -> editor_window_free(ed, win) (win is now free and ed is a pointer to win->editor) -> ed_draw(ed) use after free.

Ledger syntax highlighting breaks regex compilation

Compiled on/for OS X.

  • Died on vis.c:2080; "Could not load syntax highlighting definitions\n"
  • editor_syntax_load returns false due to regcomp(&rule->regex, rule->rule, cflags) returning REG_BADRPT on some syntax highlighting expressions.
  • Regexes that fail compilation:
    • value tag ("( |\t|^ )+?; :([^ ][^:]*:)+[ \\t]*$")
    • typed tag ("( |\t|^ )+?; [^:]+::.*",)
    • tag ("( |\t|^ )+?; [^:]+:.*")
    • metadata ("( |\t|^ )+?;.*")
    • amount ("( |\t)[^;]+?")

I am not familiar enough with the differences between the regex engines used in OSX and on the systems this would work on to fix the specific expressions that cause compilation to fail. My workaround is to remove the affected syntax highlighting definitions. I am giving this some more time to get these expressions to compile.

Control-J is identical to Enter

Control-J is the same character as Enter. This affects the binding of MOVE_LINE_DOWN in vis_movements[], which (with the introduction of multiple cursors) is now shadowed by the binding to cursors_new in vis_mode_normal[].

Non-Goals

I think the project would benefit greatly from stating some explicit non-goals. In fact, I think that in order to satisfy the stated goal summary from the README

"80% of vim's features (in other words the useful ones) implemented in roughly 1% of the code"

it is necessary to clearly delineate what kinds of things the editor will not handle. Feature creep is insidious, but good planning can head it off before it ever becomes a problem.

More checks for terminal size

The check for terminal size looks only at fd 0.

It's possible that some of the standard fds will be redirected; if fd 0 is not a tty, vis is unable to determine the proper terminal size and falls back to the curses default size.

The following patch checks fds 0, 1 and 2. Only if none of these is attached to a tty will vis fall back to the curses default size.

diff --git a/ui-curses.c b/ui-curses.c
index 569b2ca..f224e36 100644
--- a/ui-curses.c
+++ b/ui-curses.c
@@ -296,11 +296,18 @@ static void ui_resize_to(Ui *ui, int width, int height) {
    draw(ui);
 }

+static int ui_get_term_ws(struct winsize *ws) {
+   if (ioctl(0, TIOCGWINSZ, ws) == 0) return 1;
+   if (ioctl(1, TIOCGWINSZ, ws) == 0) return 1;
+   if (ioctl(2, TIOCGWINSZ, ws) == 0) return 1;
+   return 0;
+}
+
 static void ui_resize(Ui *ui) {
    struct winsize ws;
    int width, height;

-   if (ioctl(0, TIOCGWINSZ, &ws) == -1) {
+   if (!ui_get_term_ws(&ws)) {
        getmaxyx(stdscr, height, width);
    } else {
        width = ws.ws_col;

Prompt history and niceties

I feel that vis is pretty usable right now except for the barebones prompt. I know you think these kind of niceties are better implemented outside the editor. Have you considered adding readline support?

Correct typos in help text

diff --git a/config.def.h b/config.def.h
index f896647..f47d81f 100644
--- a/config.def.h
+++ b/config.def.h
@@ -238,7 +238,7 @@ static KeyAction vis_action[] = {
    },
    [VIS_ACTION_CURSOR_CHAR_NEXT] = {
        "cursor-char-next",
-       "Move cursor rigth, to the next character",
+       "Move cursor right, to the next character",
        movement, { .i = MOVE_CHAR_NEXT }
    },
    [VIS_ACTION_CURSOR_WORD_START_PREV] = {
@@ -253,7 +253,7 @@ static KeyAction vis_action[] = {
    },
    [VIS_ACTION_CURSOR_WORD_END_PREV] = {
        "cursor-word-end-prev",
-       "Move cursor bacwards to the end of word",
+       "Move cursor backwards to the end of word",
        movement, { .i = MOVE_WORD_END_PREV }
    },
    [VIS_ACTION_CURSOR_WORD_END_NEXT] = {
@@ -273,7 +273,7 @@ static KeyAction vis_action[] = {
    },
    [VIS_ACTION_CURSOR_LONGWORD_END_PREV] = {
        "cursor-longword-end-prev",
-       "Move cursor bacwards to the end of WORD",
+       "Move cursor backwards to the end of WORD",
        movement, { .i = MOVE_LONGWORD_END_PREV }
    },
    [VIS_ACTION_CURSOR_LONGWORD_END_NEXT] = {
@@ -323,7 +323,7 @@ static KeyAction vis_action[] = {
    },
    [VIS_ACTION_CURSOR_SCREEN_LINE_BEGIN] = {
        "cursor-screenline-begin",
-       "Move cursor to begin of screen/display line",
+       "Move cursor to beginning of screen/display line",
        movement, { .i = MOVE_SCREEN_LINE_BEGIN }
    },
    [VIS_ACTION_CURSOR_SCREEN_LINE_MIDDLE] = {
@@ -338,7 +338,7 @@ static KeyAction vis_action[] = {
    },
    [VIS_ACTION_CURSOR_BRACKET_MATCH] = {
        "cursor-match-bracket",
-       "Match corresponding symbol if cursor is on one of ",
+       "Match corresponding symbol if cursor is on a bracket character",
        movement, { .i = MOVE_BRACKET_MATCH }
    },
    [VIS_ACTION_CURSOR_PARAGRAPH_PREV] = {
@@ -423,12 +423,12 @@ static KeyAction vis_action[] = {
    },
    [VIS_ACTION_CURSOR_SEARCH_WORD_FORWARD] = {
        "cursor-search-word-forward",
-       "Move cursor next occurence of the word under cursor",
+       "Move cursor to next occurence of the word under cursor",
        movement, { .i = MOVE_SEARCH_WORD_FORWARD }
    },
    [VIS_ACTION_CURSOR_SEARCH_WORD_BACKWARD] = {
        "cursor-search-word-backward",
-       "Move cursor previous occurence of the word under cursor",
+       "Move cursor to previous occurence of the word under cursor",
         movement, { .i = MOVE_SEARCH_WORD_BACKWARD }
    },
    [VIS_ACTION_WINDOW_PAGE_UP] = {
@@ -503,22 +503,22 @@ static KeyAction vis_action[] = {
    },
    [VIS_ACTION_JUMPLIST_PREV] = {
        "jumplist-prev",
-       "Go to older cursor positon in jump list",
+       "Go to older cursor position in jump list",
        jumplist, { .i = -1 }
    },
    [VIS_ACTION_JUMPLIST_NEXT] = {
        "jumplist-next",
-       "Go to newer cursor positon in jump list",
+       "Go to newer cursor position in jump list",
        jumplist, { .i = +1 }
    },
    [VIS_ACTION_CHANGELIST_PREV] = {
        "changelist-prev",
-       "Go to older cursor positon in change list",
+       "Go to older cursor position in change list",
        changelist, { .i = -1 }
    },
    [VIS_ACTION_CHANGELIST_NEXT] = {
        "changelist-next",
-       "Go to newer cursor positon in change list",
+       "Go to newer cursor position in change list",
        changelist, { .i = +1 }
    },
    [VIS_ACTION_UNDO] = {
@@ -543,12 +543,12 @@ static KeyAction vis_action[] = {
    },
    [VIS_ACTION_MACRO_RECORD] = {
        "macro-record",
-       "Record macro into given regiser",
+       "Record macro into given register",
        macro_record,
    },
    [VIS_ACTION_MACRO_REPLAY] = {
        "macro-replay",
-       "Replay macro, execute the content of the given regiser",
+       "Replay macro, execute the content of the given register",
        macro_replay,
    },
    [VIS_ACTION_MARK_SET] = {
@@ -788,12 +788,12 @@ static KeyAction vis_action[] = {
    },
    [VIS_ACTION_PUT_AFTER_END] = {
        "put-after-end",
-       "Put text after the cursor, place it after new text",
+       "Put text after the cursor, place cursor after new text",
        put, { .i = PUT_AFTER_END }
    },
    [VIS_ACTION_PUT_BEFORE_END] = {
        "put-before-end",
-       "Put text before the cursor, place it after new text",
+       "Put text before the cursor, place cursor after new text",
        put, { .i = PUT_BEFORE_END }
    },
    [VIS_ACTION_CURSOR_SELECT_WORD] = {
@@ -938,12 +938,12 @@ static KeyAction vis_action[] = {
    },
    [VIS_ACTION_TEXT_OBJECT_BACKTICK_OUTER] = {
        "text-object-backtick-outer",
-       "A backtick deliminated string (outer variant)",
+       "A backtick delimited string (outer variant)",
        textobj, { .i = TEXT_OBJ_OUTER_BACKTICK }
    },
    [VIS_ACTION_TEXT_OBJECT_BACKTICK_INNER] = {
        "text-object-backtick-inner",
-       "A backtick deliminated string (inner variant)",
+       "A backtick delimited string (inner variant)",
        textobj, { .i = TEXT_OBJ_INNER_BACKTICK }
    },
    [VIS_ACTION_TEXT_OBJECT_ENTIRE_OUTER] = {
@@ -953,7 +953,7 @@ static KeyAction vis_action[] = {
    },
    [VIS_ACTION_TEXT_OBJECT_ENTIRE_INNER] = {
        "text-object-entire-inner",
-       "The whole text content, expect for leading and trailing empty lines",
+       "The whole text content, except for leading and trailing empty lines",
        textobj, { .i = TEXT_OBJ_INNER_ENTIRE }
    },
    [VIS_ACTION_TEXT_OBJECT_FUNCTION_OUTER] = {
@@ -1457,7 +1457,7 @@ static Mode vis_modes[] = {
        .default_bindings = vis_mode_normal,
    },
    [VIS_MODE_VISUAL] = {
-       .name = "--VISUAL--",
+       .name = "VISUAL",
        .isuser = true,
        .parent = &vis_modes[VIS_MODE_OPERATOR],
        .default_bindings = vis_mode_visual,
@@ -1466,7 +1466,7 @@ static Mode vis_modes[] = {
        .visual = true,
    },
    [VIS_MODE_VISUAL_LINE] = {
-       .name = "--VISUAL LINE--",
+       .name = "VISUAL LINE",
        .isuser = true,
        .parent = &vis_modes[VIS_MODE_VISUAL],
        .default_bindings = vis_mode_visual_line,
@@ -1489,7 +1489,7 @@ static Mode vis_modes[] = {
        .leave = vis_mode_prompt_leave,
    },
    [VIS_MODE_INSERT] = {
-       .name = "--INSERT--",
+       .name = "INSERT",
        .isuser = true,
        .parent = &vis_modes[VIS_MODE_READLINE],
        .default_bindings = vis_mode_insert,
@@ -1499,7 +1499,7 @@ static Mode vis_modes[] = {
        .idle_timeout = 3,
    },
    [VIS_MODE_REPLACE] = {
-       .name = "--REPLACE--",
+       .name = "REPLACE",
        .isuser = true,
        .parent = &vis_modes[VIS_MODE_INSERT],
        .default_bindings = vis_mode_replace,

Press ; to repeat last search.

In Vim if you press f or t + some-char, you can press ; to repeat that last search. This is really cool in combination with the dot to repeat stuff.

RPC Interface

This has been on my mind a lot lately, and I think it is especially relevant as vis continues to mature -- I think vis needs an RPC interface.

As I mentioned in the discussion on PR #33, I think vis is really valuable and great because of how lean it is. Marc did some good work a while back on keeping the UI decoupled from the text manipulation logic, but, as features get requested and added, it will get more and more difficult to improve the vis experience while keeping it clean and uncluttered.

Aside from completely separating UIs from the vis core, the RPC interface would allow "plugins" to be written for vis in any language. This would allow lots of auxiliary functionality (indentation, formatting, autocompletion, etc.) to be added to vis without cluttering up the core.

So I wanted to get the discussion started on the best way to approach this problem. For reference, I have been looking at the Neovim API and the Neovim Plugin Architecture. While these APIs are much bigger than we would likely want for vis, they are nonetheless a good reference point to start from.

Build broken on OpenBSD

This was introduced in 071b5f3, and is due to stdin already being defined in stdio.h

In file included from editor.c:6:
./editor.h:192:7: error: expected member name or ';' after declaration specifiers
        bool stdin;
        ~~~~ ^
/usr/include/stdio.h:206:16: note: expanded from macro 'stdin'
#define stdin   (&__sF[0])
                 ^
In file included from editor.c:6:
./editor.h:192:7: error: expected ')'
/usr/include/stdio.h:206:16: note: expanded from macro 'stdin'
#define stdin   (&__sF[0])
                 ^
./editor.h:192:7: note: to match this '('
/usr/include/stdio.h:206:15: note: expanded from macro 'stdin'
#define stdin   (&__sF[0])
                ^

I'm making an issue, as opposed to a pull request, because I don't know what to rename it to.

Change word and repeat with period

If you press c-w and enter some text, than press escape, and try to repeat this action with period, it only adds the last word, and does not change the current.

Display REPLACE mode help

diff --git a/vis.c b/vis.c
index 26b9fb4..4c5708d 100644
--- a/vis.c
+++ b/vis.c
@@ -2355,7 +2355,7 @@ static bool cmd_help(Filerange *range, enum CmdOpt opt, const char *argv[]) {
        if (mode->isuser || i == VIS_MODE_TEXTOBJ) {
            text_printf(txt, text_size(txt), "\n%s\n\n", mode->name);
            print_mode(mode, txt, i == VIS_MODE_NORMAL ||
-               i == VIS_MODE_INSERT);
+               i == VIS_MODE_INSERT || i == VIS_MODE_REPLACE);
        }
    }

Does not build on OSX since 9915b9f

Does not build on OSX since 9915b9f on OSX 10.10.2

A couple of build errors:
./config.h:79:16: error: no member named 'statuswin' in 'struct EditorWin'
wattrset(win->statuswin, focused ? A_REVERSE|A_BOLD : A_REVERSE);

In file included from vis.c:544:
./config.h:793:4: error: field designator 'statusbar' does not refer to any field in type 'Config'
.statusbar = statusbar,

vis hangs when <Tab> character is typed at prompt

Typing a character at a prompt (e.g. : or /) causes vis to enter an uninterruptible loop in keypress() because is bound to neither action nor alias for the prompt. (Perhaps this was intended to be a placeholder for tab-completion...?) Removing the incomplete binding fixes this issue:

diff --git a/config.def.h b/config.def.h
index e84629e..38e73c9 100644
--- a/config.def.h
+++ b/config.def.h
@@ -1299,7 +1299,6 @@ static KeyBinding vis_mode_prompt[] = {
    { "<Backspace>",    ACTION(PROMPT_BACKSPACE)                    },
    { "<Enter>",        ACTION(PROMPT_ENTER)                        },
    { "<C-j>",          ALIAS("<Enter>")                            },
-   { "<Tab>",                                                      },
    { /* empty last element, array terminator */                    },
 };

incorrect display when file begins with a multibyte character

When the first character of a file is a multibyte character, vis displays a sequence of Unicode REPLACEMENT CHARACTER.

I believe that the cause is the use of an anonymous (i.e. NULL) mbstate_t* object in the call to mbrtowc() in view_draw(). While this might actually be a bug in the implementation of mbrtowc(), it is avoided by use of an explicitly initialized mbstate_t object.

Here's a short patch:

diff --git a/view.c b/view.c
index d49c417..80f7038 100644
--- a/view.c
+++ b/view.c
@@ -349,6 +349,8 @@ void view_draw(View *view) {
    memset(match, 0, sizeof match);
    /* default and current curses attributes to use */
    int default_attrs = COLOR_PAIR(0) | A_NORMAL, attrs = default_attrs;
+  /* start from known multibyte state */
+  mbstate_t mbstate = { 0 };

    while (rem > 0) {

@@ -403,7 +405,7 @@ void view_draw(View *view) {
            }
        }

-       size_t len = mbrtowc(&wchar, cur, rem, NULL);
+       size_t len = mbrtowc(&wchar, cur, rem, &mbstate);
        if (len == (size_t)-1 && errno == EILSEQ) {
            /* ok, we encountered an invalid multibyte sequence,
             * replace it with the Unicode Replacement Character

Storing undo history to disk

I understand the algorithm already supports infinite undo history, but are you planning on adding support for saving this history to disk, so you can undo/redo if you open a file later?

libtermkey is EOL

As state on its website

Note: This project is now DEAD; end-of-life. There will likely be no further releases.

So why is vis using it?

ruler and line numbers

With current head on OS X 10.10:

  1. the ruler (row, col) doesn't get updated until ':' is pressed;
  2. are line numbers window-local?
    (They disappear from top/left when window is split, except for C/C++ files.)

Cancelling wildcard open causes crash

Invoke a wildcard open as

:edit *.c

Then cancel (ctrl-c) without selecting a file. This causes vis to close the open window. Subsequent motion commands (e.g. ctrl-d) may cause a segfault.

The following patch corrects the behavior:

diff --git a/vis.c b/vis.c
index a4917e9..6c46979 100644
--- a/vis.c
+++ b/vis.c
@@ -1776,7 +1776,7 @@ static bool openfiles(const char **files) {
    for (; *files; files++) {
        const char *file = file_open_dialog(*files);
        if (!file)
-           continue;
+           return false;
        errno = 0;
        if (!vis_window_new(file)) {
            editor_info_show(vis, "Could not open `%s' %s", file,

I'm not sure it's the best possible patch, but it works.

Note that openfiles may accept multiple files or patterns. In practice, it seems to be always called with a single file or pattern. This patch will be OK so long as the existing calling pattern is maintained. I'm not convinced that all uses of openfiles will do the right thing if called with multiple files or patterns.

get rid of syntax highlighting

Maintaining syntax files and parsing is not worth it for the colorful distraction. Efficiency would be improved, too.
See also syntax off

Edit: unless you're doing this to challenge yourself

Autocompletion in prompt

It would be great to have some autocompletion in the prompt, like for set syntax <tab> to get all available syntaxes, or r <tab> to get every files in the current folder.

Valgrind issues

I played a bit with valgrind, and it found several issues:

==29080== Memcheck, a memory error detector
==29080== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==29080== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==29080== Command: ./vis
==29080== Parent PID: 26074
==29080== 
==29080== Conditional jump or move depends on uninitialised value(s)
==29080==    at 0x4F0379B: re_compile_fastmap_iter.isra.25 (regcomp.c:328)
==29080==    by 0x4F136BC: re_compile_fastmap (regcomp.c:276)
==29080==    by 0x4F13DF0: regcomp (regcomp.c:512)
==29080==    by 0x402E06: editor_syntax_load (editor.c:274)
==29080==    by 0x412E6D: main (vis.c:2079)
==29080==  Uninitialised value was created by a heap allocation
==29080==    at 0x4C2ABA0: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==29080==    by 0x4F10DFB: create_token_tree (regcomp.c:3745)
==29080==    by 0x4F10DFB: parse_expression (regcomp.c:2234)
==29080==    by 0x4F11BBB: parse_branch.constprop.32 (regcomp.c:2186)
==29080==    by 0x4F1247D: parse_reg_exp (regcomp.c:2145)
==29080==    by 0x4F1247D: parse (regcomp.c:2114)
==29080==    by 0x4F1247D: re_compile_internal (regcomp.c:794)
==29080==    by 0x4F13DDF: regcomp (regcomp.c:501)
==29080==    by 0x402E06: editor_syntax_load (editor.c:274)
==29080==    by 0x412E6D: main (vis.c:2079)
==29080== 
==29080== Conditional jump or move depends on uninitialised value(s)
==29080==    at 0x4F0379B: re_compile_fastmap_iter.isra.25 (regcomp.c:328)
==29080==    by 0x4F136FC: re_compile_fastmap (regcomp.c:280)
==29080==    by 0x4F13DF0: regcomp (regcomp.c:512)
==29080==    by 0x4109CB: cmd_set (vis.c:1368)
==29080==    by 0x412012: exec_cmdline_command (vis.c:1802)
==29080==    by 0x4120FE: exec_command (vis.c:1821)
==29080==    by 0x40F8A3: prompt_enter (vis.c:1035)
==29080==    by 0x4128D0: keypress (vis.c:1973)
==29080==    by 0x412D23: mainloop (vis.c:2055)
==29080==    by 0x413113: main (vis.c:2118)
==29080== 
==29080== Conditional jump or move depends on uninitialised value(s)
==29080==    at 0x4F0379B: re_compile_fastmap_iter.isra.25 (regcomp.c:328)
==29080==    by 0x4F1371C: re_compile_fastmap (regcomp.c:282)
==29080==    by 0x4F13DF0: regcomp (regcomp.c:512)
==29080==    by 0x4109CB: cmd_set (vis.c:1368)
==29080==    by 0x412012: exec_cmdline_command (vis.c:1802)
==29080==    by 0x4120FE: exec_command (vis.c:1821)
==29080==    by 0x40F8A3: prompt_enter (vis.c:1035)
==29080==    by 0x4128D0: keypress (vis.c:1973)
==29080==    by 0x412D23: mainloop (vis.c:2055)
==29080==    by 0x413113: main (vis.c:2118)
==29080== 
==29080== 
==29080== HEAP SUMMARY:
==29080==     in use at exit: 782,415 bytes in 1,856 blocks
==29080==   total heap usage: 26,783 allocs, 24,927 frees, 5,659,040 bytes allocated
==29080== 
==29080== For a detailed leak analysis, rerun with: --leak-check=full
==29080== 
==29080== For counts of detected and suppressed errors, rerun with: -v
==29080== ERROR SUMMARY: 11 errors from 3 contexts (suppressed: 0 from 0)

Here is the command I used:

valgrind --track-origins=yes --leak-check=no --log-file=val.txt ./vis

I redirected the output, since vis was messing with it.

The suppr key is not working.

Step to reproduce:

  1. select a piece of text in visual mode
  2. try to delete it with the suppr key

Expected result

The text should be deleted.

Actual result

Nothing happens.

Cursor position issues

When changing from insert to normal mode, the cursor doesn't move back one column as it does in vi and vim. Not sure if this is an oversight or a conscious decision.

Also, the cursor's column position gets decreased when it enters a row with fewer columns than the previous row. So instead of the cursor displaying in column 5 for any rows with >= 5 columns and displaying in the last column for any shorter columns, entering into a row with, say, 3 columns will actually change the cursor's position.

^b gets converted to backspace

CONTROL('B') is set to wscroll, -PAGE at line 394 of config.def.h, but ui_getkey() overrides it. Removing line 566 of ui-curses.c addresses this, or at least seems to prove why the mapping doesn't work.

vis crashes with too many windows

Attempting to create more windows than will fit on the screen causes vis to segfault. This can be trigged either via repeated application of :new or by attempting to open many files from the command line.

This really isn't that serious since there's no good way to use vis with a lot of windows: vis lacks commands to manipulate window size and visibility. One quickly learns to only open as many files as the screen size will comfortably accommodate.

Makefile broken for parallel execution

The "all" rule has "clean" and "options" as dependencies because those are not dependent on each other make can execute them in any order which leads to sometimes clean being executed after building vis when you use "make -j".

Poor performance on large $COLUMNS

I have quite a high resolution and sometimes my terminal width has COLUMNS > 200.

vis slows down drastically and chews up a lot of CPU... it seems that it doesn't scale well with the length of lines (even if they don't contain text)?

Cant Make the project

In file included from editor.c:5:0:
editor.h:4:20: fatal error: curses.h: No such file or directory
#include <curses.h>
^
compilation terminated.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.