Giter Club home page Giter Club logo

onivim / libvim Goto Github PK

View Code? Open in Web Editor NEW
682.0 22.0 33.0 102.51 MB

libvim: The core Vim editing engine as a minimal C library

Home Page: https://v2.onivim.io

License: MIT License

Makefile 0.94% Vim Script 56.32% C 38.55% Roff 2.21% Awk 0.09% Perl 0.30% HTML 0.01% MATLAB 0.01% Tcl 0.01% Batchfile 0.02% Shell 0.18% PostScript 0.30% Python 0.11% Smalltalk 0.12% Emacs Lisp 0.14% JavaScript 0.13% NewLisp 0.18% Ruby 0.17% SystemVerilog 0.13% C++ 0.06%
vim c onivim libvim text-editor vi

libvim's Introduction

Build Status

What is libvim?

libvim is a fork of Vim, with the goal of providing a minimal C-based API, modelling Vim modal editing. It does not include any user interface at all (not even a terminal UI), and is primarily responsible for acting as a fast buffer manipulation engine, faithful to Vim keystrokes. It's still a work-in-progress and there is lots of work left to stabilize.

If you're looking for a terminal Vim, check out neovim, or a GUI Vim, check out Onivim 2.

Why?

libvim is primarily intended for Onivim 2. After implementing several iterations of 'UI Vims' between v1, v2, and other projects, the abstraction I wished to have was a sort of a pure functional Vim, completely decoupled from terminal UI - where 'vim' is a function of (editor state, input) => (new editor state). As Onivim 2 completely handles the rendering layer, this Vim-modelled-as-a-pure-function could focus on just buffer manipulation.

To that end, libvim exposes a simple C API for working with Vim, and supports listening to buffer changes, messages, etc.

It is responsible for:

  • Managing and manipulating buffers
  • Buffer manipulation in response to input
  • Parsing and sourcing VimL
  • Handling key remaps

It is NOT responsible for:

  • Any sort of UI rendering (terminal, etc)
  • Mouse support
  • Syntax Highlighting
  • Spell Checking
  • Terminal Support
  • Completion
  • Input methods (IME)

All of these are intended to be handled by the consumer of the library - leaving libvim to be focused on the job of fast buffer manipulation.

libvim builds cross-platform (since Onivim 2 requires it!), as well as for WebAssembly - we'd like to port our v1 tutorials to a browser-based experience.

There are other interesting applications of such an 'abstracted Vim':

  • WebAssembly builds could be useful for implementing Vim modes in browsers / websites
  • Native builds could be useful for applications that want Vim-native bindings - it'd be a nice foundation for implementing readline, for example.

API

For an example of the API usage, check out the apitests like normal_mode_motion. The full API is available here: libvim.h

The heart of the API is vimInput which takes a single key, and is synchronously processed by the state machine. 'Side-effects' like buffer updates, messages, etc can be subscribed to via callbacks like vimSetBufferUpdateCallback.

This library is in active development and we currently make no guarantees about backwards compatibility. Use the API at your own risk.

Compiling

Install esy

esy is like npm for native code. If you don't have it already, install it by running:

npm install -g [email protected]

Get sources

  • git clone https://github.com/onivim/libvim
  • cd src

Installing dependencies

  • esy install
  • esy '@test' install

Building

  • esy build

Running tests

  • esy '@test' build

Development

The esy workflow works great for one-off builds, but will rebuild the world every time, so during development it's better to have an incremental workflow.

Building & running tests incrementally

  • cd src
  • make apitest/autoindent.test.exe
  • cd apitest
  • ./autoindent.test.exe

Testing changes against Onivim 2

You can test a locally-built libvim against a locally-built Onivim 2 by adding a resolution in the Onivim 2 package.json, like:

"resolutions": {
	...
	"libvim": "link:../libvim/src"
}

Just make sure it points to the libvim/src folder.

NOTE: We've seen issues with this workflow where the binaries can be out-of-date in Onivim 2, so we recommend running rm -rf _esy && esy i after each change to rebuild the dependency.

FAQ

Why is libvim based on Vim and not Neovim?

I'm a huge fan of the work the Neovim team is doing (and the team has been incredibly supportive of the Onivim project). Ideally, we would've stuck with Neovim or implemented libvim based on libnvim. In fact, the first time I tried to build this 'minimal abstraction' - I tried to base it off Neovim's libnvim. I timeboxed the investigation to 2 days, and ran into some serious hurdles - our build environment is a bit challenging on Windows (it's based on Cygwin + MingW cross-compiler toolchain) - I encountered several issues getting Neovim + deps to build in that environment. Based off that spike, I estimated it would take ~3-4 weeks to get it working in that toolchain.

Note that this is not a Neovim issue - the dependency usage and leveraging of CMake are good decisions - it's a consequence of our OCaml build system. The Cygwin + MingW cross-compiler toolchain isn't well handled by all dependencies (being a weird hybrid of Win32 and Unix, it's often the case where #ifdefs are wrong, incorrect dependencies are pulled in, and it can be a huge time sink working through these issues).

Vim, in contrast, was able to compile in that environment easily (NOTE: If anyone is interested in building a cross-platform, esy-enabled Neovim package - we can revisit this!). I'm also interested in WebAssembly builds, for porting the Onivim v1 tutorials to the web, in which this C-abstracted library compiled to WebAssembly would be a perfect fit.

Beyond the build issues, both Neovim and Vim would need refactoring to provide that synchronous, functional API:

  • Neovim uses an event loop at its core, which would need to be short-circuited or removed to provide that API
  • Vim uses blocking input, which would need to be inverted to support the functional API

The motivation of all this work was to remove the RPC layer from Onivim v2 to reduce complexity and failure modes - at the end, this was purely a constraint-based technical decision. If we can get a similar API, buildable via esy cross-platform, with nvim - I'd be happy to use that :)

Supporting

If libvim is interesting to you, and you'd like to support development, consider the following:

Contributing

If you would like to help making libvim better, see the CONTRIBUTING.md file.

Some places for contribution:

License

libvim code is licensed under the MIT License.

It also depends on third-party code, notably Vim, but also others - see ThirdPartyLicenses.txt for license details.

libvim's People

Contributors

brammool avatar bryphe avatar city41 avatar crossr avatar glennsl avatar mtippett avatar sghill 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

libvim's Issues

vim crash after calling vimSearchGetHighlights after a canceled visual search/replace

Describe the bug
While in visual mode and in the middle of a search and replace, ie :s/foo/bar, then cancel by pressing esc, then calling vimSearchGetHighlights, vim can crash

To Reproduce
run this test (I added it to cmdline_search.c)

MU_TEST(test_get_search_highlights_during_visual)
{
  int vim_num_search_highlights;
  searchHighlight_T *vim_search_highlights;

  vimInput("V");
  vimKey("<down>");
  vimKey("<down>");
  vimInput(":s/vvvv");
  vimKey("<esc>");

  vimSearchGetHighlights(1, 3, &vim_num_search_highlights, &vim_search_highlights);
}

It will crash with this

-- START test_get_search_highlights_during_visual --
=================================================================
==297823==ERROR: AddressSanitizer: heap-use-after-free on address 0x60b0000003b7 at pc 0x7fa720372917 bp 0x7ffd27057950 sp 0x7ffd270570f8
READ of size 1 at 0x60b0000003b7 thread T0
    #0 0x7fa720372916  (/lib/x86_64-linux-gnu/libasan.so.5+0xd7916)
    #1 0x55d3560c56f1 in vim_regcomp (/home/matt/dev/libvim/src/_esy/test/store/b/libvim-db9de2ae/apitest/cmdline_search.test.exe+0x986f1)
    #2 0x55d3560d797f in search_regcomp (/home/matt/dev/libvim/src/_esy/test/store/b/libvim-db9de2ae/apitest/cmdline_search.test.exe+0xaa97f)
    #3 0x55d3560d8665 in searchit (/home/matt/dev/libvim/src/_esy/test/store/b/libvim-db9de2ae/apitest/cmdline_search.test.exe+0xab665)
    #4 0x55d356059917 in vimSearchGetHighlights (/home/matt/dev/libvim/src/_esy/test/store/b/libvim-db9de2ae/apitest/cmdline_search.test.exe+0x2c917)
    #5 0x55d356057293 in test_get_search_highlights_during_visual apitest/cmdline_search.c:28
    #6 0x55d356058742 in test_suite apitest/cmdline_search.c:119
    #7 0x55d356058cbb in main apitest/cmdline_search.c:134
    #8 0x7fa71f5b10b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
    #9 0x55d3560569ad in _start (/home/matt/dev/libvim/src/_esy/test/store/b/libvim-db9de2ae/apitest/cmdline_search.test.exe+0x299ad)

entire crash output here: https://gist.github.com/city41/ab6d14b3ffd3494e6e4f01e8b3dc5f66

Expected behavior
should not crash

Environment (please complete the following information):

  • Vim version: master branch of libvim
  • OS: Ubuntu MATE 20.04
  • Terminal: mate-terminal

Passing commands one character at a time breaks keybinds

Describe the bug

If input is passed to vimInput one character at a time a multi-character keybind (for example inoremap jk <esc>) will fail. The first key will be swallowed up and the second will be inputted, without leaving insert mode.

To Reproduce

This test passes

diff --git a/src/apitest/insert_mode.c b/src/apitest/insert_mode.c
index bb87cfe01..ff8e3f68b 100644
--- a/src/apitest/insert_mode.c
+++ b/src/apitest/insert_mode.c
@@ -168,6 +168,19 @@ MU_TEST(insert_mode_ctrlv_newline)
   mu_check(line[0] == 13);
 }

+MU_TEST(insert_mode_exits_with_keybind)
+{
+  vimExecute("inoremap jk <esc>");
+  vimInput("i");
+  vimInput("jk");
+
+  mu_check((vimGetMode() & NORMAL) == NORMAL);
+
+  char_u *line = vimBufferGetLine(curbuf, vimCursorGetLine());
+  printf("LINE: %s\n", line);
+  mu_check(strcmp(line, "abc") == 0);
+}
+
 MU_TEST_SUITE(test_suite)
 {
   MU_SUITE_CONFIGURE(&test_setup, &test_teardown);
@@ -182,6 +195,7 @@ MU_TEST_SUITE(test_suite)
   MU_RUN_TEST(insert_mode_ctrlv);
   MU_RUN_TEST(insert_mode_ctrlv_no_digit);
   MU_RUN_TEST(insert_mode_ctrlv_newline);
+  MU_RUN_TEST(insert_mode_exits_with_keybind);
 }

whereas this test fails

diff --git a/src/apitest/insert_mode.c b/src/apitest/insert_mode.c
index bb87cfe01..837cae897 100644
--- a/src/apitest/insert_mode.c
+++ b/src/apitest/insert_mode.c
@@ -168,6 +168,20 @@ MU_TEST(insert_mode_ctrlv_newline)
   mu_check(line[0] == 13);
 }

+MU_TEST(insert_mode_exits_with_keybind)
+{
+  vimExecute("inoremap jk <esc>");
+  vimInput("i");
+  vimInput("j");
+  vimInput("k");
+
+  mu_check((vimGetMode() & NORMAL) == NORMAL);
+
+  char_u *line = vimBufferGetLine(curbuf, vimCursorGetLine());
+  printf("LINE: %s\n", line);
+  mu_check(strcmp(line, "abc") == 0);
+}
+
 MU_TEST_SUITE(test_suite)
 {
   MU_SUITE_CONFIGURE(&test_setup, &test_teardown);
@@ -182,6 +196,7 @@ MU_TEST_SUITE(test_suite)
   MU_RUN_TEST(insert_mode_ctrlv);
   MU_RUN_TEST(insert_mode_ctrlv_no_digit);
   MU_RUN_TEST(insert_mode_ctrlv_newline);
+  MU_RUN_TEST(insert_mode_exits_with_keybind);
 }

Expected behavior

Oni2 sends keystrokes one at a time to vimInput. Because of this, the above behavior is blocking implementing Spacemacs-like keybindings. I would like to see this fixed here or for some other solution for spooling keypress before sending to vimInput implemented on the Oni2 side.

Support for spellsuggest

(Really appreciate your work on this - really is a valuable library for anyone building a vim-like editor)

Most vim commands work as expected with vim.Execute(...). Looking through the code it looks like spellsuggest would be supported and that the sequence:

vimExecute("let sug = spellsuggest('hellllo')")
s = vimEval("string(sug)")

should bring back the suggestions in a stringified list. What I get is always an empty list.

I have tried to place the spelling and suggestion files in a variety of places and explicitly set the file locations via "set spell spelllang=...". Nothing has worked.

Is executing the spellsuggest command supported by libvim?

[Feature] Expose command state

There's currently no way to inspect the command state, i.e. which keys have been punched in and what command is in the process of being built. Knowing this would be useful for a couple of features:

  1. Displaying the current command state, which characters and what count, if any, has been entered, in case you get distracted in the middle of something and forget.

  2. To provide contextual help. This will both reduce the need to memorize commands AND make it easier to learn them. For example, if g has been entered, the UI could display a list of possible characters to "complete" the command:

g - Go to top
t - Go to next tab
T - Go to previous tab
u - Convert to lowercase
U - Convert to uppercase
~ - Swap case
] - See all definitions

Technical details

The command state, at least in normal mode, is stored in state_current->context->ca, a cmdarg_T. state_current->context is a void* and will point to different data structures depending on mode, but normal mode is mostly what I'm interested in here (or "Normal", "Visual" and "Operator" I guess, according to get_real_state()).

A new function vimGetCommandState could return either the entire cmdarg_T struct, or a subset if that's easier to bind to from Reason. Or null if the stars aren't aligned.

Manually build headers error: Vim only works with 32 bit int or larger

Instructions: Replace the template text and remove irrelevant text (including this line)

Describe the bug
I tired to build this library with build/build-posix.sh on arch linux, only to find the generated headers has a bunch of errors in it.
The generated header files & static library can't be build to another program with the following commands because of the errors in it.

gcc -g -I./include test.c -o out -L./lib -lvim

To Reproduce

  1. set environment variable cur_install to "/tmp/libvim-test-export"
  2. run build/build-posix.sh
  3. open vim.h under generated include path

Expected behavior
No errors

Screenshots
image

Environment (please complete the following information):

  • libvim version: last commit 9ade7d1
  • OS: Linux arch 5.13.9-arch1-1 #1 SMP PREEMPT Sun, 08 Aug 2021 11:25:35 +0000 x86_64 GNU/Linux
  • Terminal: alacritty (does that matter?)

vim #defines leak out to rest of app

Is your feature request related something that is currently hard to do? Please describe.
vim contains very "generic" defines such as #define OK 1. When using vim as a library, these defines can leak out to the rest of the app and cause some grief.

Describe the solution you'd like
I am unsure of a truly good solution. But maybe libvim.h should not include vim.h, which pulls in all of vim, but rather pull in a more strategic set of files?

Another possible solution is to namespace these defines, like #define VIM_OK 1 but can certainly understand why changing vim's code is not so great.

And of course, another solution is just ignore this problem. I suppose it depends on how far libvim gets used. If it really only ever powers Oni, then this might not matter.

Describe alternatives you've considered
I have used #undef after #includeing libvim.h, which patches the problem. But since I don't know what defines vim has made, I am unsure when/if this will bite me again in the future.

step backwards from neovim?

Seems like one of neovim's original goals was to go from sync key handling to async key handling to improve performance. This takes a step back, back to sync handling.

Will this have the issues that Neovim solved (namely vim plugins that slow the user experience down, f.e. long wait times to process key press actions, especially movement actions), once we start adding various Vim plugins?

Conan package support

Is your feature request related something that is currently hard to do? Please describe.
Conan is a dependency manager for c/c++, seeing as this is a custom library it's not exactly easy to find in most main stream package managers though(to my knowledge) is very good about allowing smaller packages into it's primary "repo", or creating a cmake-hunter build so that it can be consumed like that

Describe the solution you'd like
I'd prefer conan but something closer to resembling a traditional c/c++ build system would make the project easier to ingest into existing projects.

Describe alternatives you've considered
providing a more traditional build system(cmake/makefile/ninja) so that creating a git submodule and just integrating into an existing project is easier.

Additional context
Conan website: https://conan.io/
Hunter Git repo: https://github.com/cpp-pm/hunter

test

Instructions: Replace the template text and remove irrelevant text (including this line)

Describe the bug
A clear and concise description of what the bug is.
(Issues related to the runtime files should be reported to their maintainer, check the file header.)

To Reproduce
Detailed steps to reproduce the behavior:

  1. Run vim --clean (or gvim --clean, etc.)
  2. Edit filename
  3. Type '....'
  4. Describe the error

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, copy/paste the text or add screenshots to help explain your problem.

Environment (please complete the following information):

  • Vim version [e.g. 8.1.1234] (Or paste the result of vim --version.)
  • OS: [e.g. Ubuntu 18.04, Windows 10 1809, macOS 10.14]
  • Terminal: [e.g. GNOME Terminal, mintty, iTerm2, tmux, GNU screen] (Use GUI if you use the GUI.)

Additional context
Add any other context about the problem here.

WebAssembly build

Can you give some advice how to compile libvim to WebAssembly? its mentioned in the README.md but I could not find any instructions how this is done.

I do not know the esy tool very well, but I think I was able to build the library under linux using this script in src/build (running it from src):

# build in this folder
cur__install=my_build_wasm
# the lib folder is not created by the makefile for some reason -> created it manually
mkdir -p $cur__install/lib
emconfigure ./configure --disable-selinux CFLAGS=-fPIC
emmake make installlibvim DESTDIR=$cur__install

There were some failing checks though (not sure if this is the problem):

checking --with-tlib argument... empty: automatic terminal library selection
checking for tgetent in -ltinfo... no
checking for tgetent in -lncurses... no
checking for tgetent in -ltermlib... no
checking for tgetent in -ltermcap... no
checking for tgetent in -lcurses... no
no terminal library found
checking for tgetent()... configure: error: NOT FOUND!
      You need to install a terminal library; for example ncurses.
      Or specify the name of the library with --with-tlib.

Anyway I got a libvim.a file and tried compiling this code:

#include <stdio.h>
#include "libvim.h"

void sayHello() {
        printf("hello\n");
}

int main(int argc, char** argv) {
        vimInit(argc, argv);
        sayHello();
}

using this command:

emcc -Iinclude -Iinclude/proto -DHAVE_CONFIG_H -fPIC main.c lib/libvim.a -o index.html

But then I got this error:

wasm-ld: error: unknown file type: libvim.o

This works fine using gcc:

# after running the same build script but with configure/make instead of emconfigure/emmake
gcc -Iinclude -Iinclude/proto -DHAVE_CONFIG_H main.c lib/libvim.a -lSM -lICE -lXt -lX11 -lXdmcp -lm -ltinfo -lnsl -ldl

Any idea what could be wrong? Did you have success using this library with WebAssembly yet? If so it would be great if you could add some directions how.

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.