gchp / iota Goto Github PK
View Code? Open in Web Editor NEWA terminal-based text editor written in Rust
License: MIT License
A terminal-based text editor written in Rust
License: MIT License
When you hold down the arrow keys for longer than a fee seconds, there is a strange flickering. Not sure what is causing it. Could be an issue with rustbox, not sure through.
Allow finding and matching results concurrently while editing (including searching the in-progress buffer). This should be especially useful with large files. The results may be slightly stale, but there are ways of "fixing up" most results.
Doing this in a nonblocking way requires consistent use of transactions and MVCC, so it is not an easy problem, but it is a solved one and it would be really useful in a text editor.
When I quit iota it returns to the command line but does not exit until I press ctrl-c. Commit dcd5808 built with rustc 0.13.0-nightly (8bca470c5 2014-12-08 00:12:30 +0000). Ubuntu 14.04.
If you undo/redo from more than a screen away, Iota crashes ignominiously.
Thinking about things like saving a file, displaying errors, etc., we should have a standard interface for communicating with the user. Things to think about:
@gchp mentioned that vigo has the concept of an Overlay. We should look into that.
LET (result set) := MAP (set expression of positions) (position => sequence expression of characters)
Data modification should be of the form:
The ? is where we calculate the series of very simple operations from higher level actions. We would calculate cursor position here too, I think.
This is a very rough draft idea and I am highly open to changes.
"High level" user facing language example (semantics, not syntax!):
TRANSACTION1 := MAP (POSITION(character) WHERE LINE(character) = LINE($CURSOR) OR LINE(character) = NEXT(LINE($CURSOR))) (position => [])
TRANSACTION2 := DELETE character WHERE POSITION(character) = POSITION(NEXT($CURSOR))"
Note that this is data modification. Cursor math is entirely separate from data modification--such queries do not move the cursor at all intrinsically, but may be updated in individual transactions (which can see values updated by old transactions):
POSITION($CURSOR) := MAX(POSITION(character)) WHERE DELETED(TRANSACTION1,character)
It seems like the "after" cursor isn't being set correctly currently, so when you redo the cursor ends up in the wrong place (i.e. not the place it was before the edit began). Seems like this should be an easy fix.
Like iota
, but screenshot looks old (because in header there is rdit
). Would be nice if you could update this.
I don't like the name 'rdit'. It was never meant to be temporary, so I'm going to rename it.
Some possible names I have right now (all playing on the words rust and editor):
Not really mad about any of them, though. Opening this issue to track names I may come up with in the future.
I was going to implement a few ones but saw that @gchp already did.
I see a few problemas:
Hey, I left a comment on your HN posting about The Craft of Text Editing. I've been thinking about both a) implementing a text editor & b) learning Rust for several months now, and I'd like to contribute. I fiddled with a text editor in Python a while ago, which is when I found that book.
I notice that buffer.rs implements the buffer as a vector of vectors of chars. This is the obvious way to do it, but as I discovered from The Craft of Text Editing, its much more efficient to implement it as a gap buffer - a resizing array with with a moveable gap (see chapter 6 or Wikipedia for more info). A generic gap buffer seems like a good introduction to Rust, so I've started working on it. Ultimately I'll implement the same API as the current buffer and submit a pull request?
I can’t type capital letters or any of the non-ASCII characters I tried. Every valid character seems to be hardcoded in src/iota/keyboard.rs
, so I guess that’d have to be changed to be more general.
Hey,
currently try to install iota on a Windows (32bit) machine. Have installed everything right, but running cargo build
returns following error:
$ cargo build
Compiling termbox-sys v0.0.1 (http://github.com/gchp/rustbox#9f6ca3c6)
Failed to run custom build command for `termbox-sys v0.0.1 (http://github.com/gchp/rustbox#9f6ca3c6)`
Process didn't exit successfully: `C:\users\droekm\documents\githubrepos\iota\target\build\termbox-sys-0aa44b9f7c4b257e\build-script-build.exe` (status=101)
--- stdout
waf configure: setting CFLAGS to: `-m32`
running: ./waf 'configure' '--prefix=/'
--- stderr
task '<main>' panicked at 'called `Result::unwrap()` on an `Err` value: file not found (OS Error 2: The system cannot find file
)', C:\bot\slave\nightly-win-32\build\src\libcore\result.rs:744
running on MSYS, also tried from normal command prompt but same error. what can I do?
Regards,
Jan
Right now, vertical scrolling works, however horizontal scrolling does not.
rdit is somewhat cpu intensive right now as it is drawing constantly, regardless of the status of the buffer. Need to change this to only draw when the buffer changes.
The Editor
should store multiple buffers.
As I see it, a View
should be able to attach to, or detach from a given buffer in the list of buffers.
Probably need to add the ability to load a new file in the current buffer first, then change it to load into a new buffer afterwards, with the ability to switch back and forth.
See here for an example of how the vigo
editor does this. Adapting this could be a good starting place.
I installed Rust & cargo on my Mac (OSX Yosemite) with
curl -sS https://static.rust-lang.org/rustup.sh | sudo bash
when I try to build Iota with cargo build --verbose
I get the following error:
Fresh docopt v0.6.13
Fresh termbox-sys v0.0.1 (http://github.com/gchp/rustbox#9f6ca3c6)
Fresh rustbox v0.1.0 (http://github.com/gchp/rustbox#9f6ca3c6)
Compiling iota v0.1.0 (file:///Users/christopher/Developer/iota/iota)
Running `rustc src/iota/lib.rs --crate-name iota --crate-type lib -g -C metadata=42040d39621a544d -C extra-filename=-42040d39621a544d --out-dir /Users/christopher/Developer/iota/iota/target --dep-info /Users/christopher/Developer/iota/iota/target/.fingerprint/iota-42040d39621a544d/dep-lib-iota -L /Users/christopher/Developer/iota/iota/target -L /Users/christopher/Developer/iota/iota/target/deps --extern rustbox=/Users/christopher/Developer/iota/iota/target/deps/librustbox-2d654b153b211ab3.rlib --extern docopt=/Users/christopher/Developer/iota/iota/target/deps/libdocopt-b7d89a28702de1cc.rlib -L /Users/christopher/Developer/iota/iota/target/build/termbox-sys-27e77d5199c67e79/out/lib`
src/iota/keyboard.rs:91:9: 91:14 error: cannot move out of dereference of `&`-pointer
src/iota/keyboard.rs:91 *self as u32
^~~~~
error: aborting due to previous error
Could not compile `iota`.
Caused by:
Process didn't exit successfully: `rustc src/iota/lib.rs --crate-name iota --crate-type lib -g -C metadata=42040d39621a544d -C extra-filename=-42040d39621a544d --out-dir /Users/christopher/Developer/iota/iota/target --dep-info /Users/christopher/Developer/iota/iota/target/.fingerprint/iota-42040d39621a544d/dep-lib-iota -L /Users/christopher/Developer/iota/iota/target -L /Users/christopher/Developer/iota/iota/target/deps --extern rustbox=/Users/christopher/Developer/iota/iota/target/deps/librustbox-2d654b153b211ab3.rlib --extern docopt=/Users/christopher/Developer/iota/iota/target/deps/libdocopt-b7d89a28702de1cc.rlib -L /Users/christopher/Developer/iota/iota/target/build/termbox-sys-27e77d5199c67e79/out/lib` (status=101)
My terminal background color is white, so when I use iota
the foreground color is almost the same as the background color, making it really hard to see the text.
I think that iota
should set the background color to black or something if possible.
Since #33 was merged, there's a bunch of failing tests. The build works fine, just the tests need to be updated.
really like iota, have tried it under linux but also not getting work on windows (like #25). would be nice if you can add some more screenshots (wiki page for it?) or a short screencast ;)
It would be great to have some kind of simple configuration file which users could use to tweak Iota behaviour. Things like using spaces or tabs, tab width, and so on.
Rust projects seem to use toml a lot for configuration files. Perhaps this would be a good starting place?
[config]
spaces = true
tabwidth = 4
or similar?
In the future there will be a proper plugin system, but we need something simple to start with.
Lines don't draw properly if there are tab (\t
) characters in the data. Need to refactor to take special characters into account.
I get the following error:
$ cargo test
Updating git repository `https://github.com/gchp/rustbox`
Updating registry `https://github.com/rust-lang/crates.io-index`
Updating git repository `https://github.com/gchp/termbox-sys`
Downloading docopt v0.6.16
Compiling termbox-sys v0.0.2 (https://github.com/gchp/termbox-sys#e8352762)
Compiling docopt v0.6.16
/Users/ruipacheco/.cargo/registry/src/github.com-1ecc6299db9ec823/docopt-0.6.16/src/parse.rs:45:34: 45:40 error: unresolved import `std::collections::hash_map::Vacant`. There is no `Vacant` in `std::collections::hash_map`
/Users/ruipacheco/.cargo/registry/src/github.com-1ecc6299db9ec823/docopt-0.6.16/src/parse.rs:45 use std::collections::hash_map::{Vacant, Occupied};
^~~~~~
/Users/ruipacheco/.cargo/registry/src/github.com-1ecc6299db9ec823/docopt-0.6.16/src/parse.rs:45:42: 45:50 error: unresolved import `std::collections::hash_map::Occupied`. There is no `Occupied` in `std::collections::hash_map`
/Users/ruipacheco/.cargo/registry/src/github.com-1ecc6299db9ec823/docopt-0.6.16/src/parse.rs:45 use std::collections::hash_map::{Vacant, Occupied};
^~~~~~~~
error: aborting due to 2 previous errors
Build failed, waiting for other jobs to finish...
Could not compile `docopt`.
To learn more, run the command again with --verbose.
This relates mainly to #23 and #52.
Currently, the use of a rustbox interface is pretty deeply entangled with text manipulation; this seems inadvisible - if iota is successful enough, people will want other interfaces (such as graphical ones). The user interface and the actual editor should be isolated from one another.
I would propose to have the front end and back end communicate over a fully developed query language as described in #52. The back end will essentially be an interpreter for the query language; the initial front-end will be a termbox interface which produces query semantics from the user's terminal interaction, but other front-ends could ultimately be developed which are programmatic or otherwise different.
Currently, the structure of the program is that an editor owns a view which owns a buffer and a uibuf; user input passes through the editor to the view which results in changes to the buffer, then the view draws a portion of the buffer to the uibuf. Instead, the core of the back-end should be a dispatcher which owns all the buffers that have been loaded (accomplishing #23). It listens for queries and performs the first step of interpretation: determining the context in which the remainder of the interpretation should be performed. It then creates a separate thread which performs the interpretation and passes a result back - this result is then sent back to the client.
The context of the interpretation includes two main components: first, the buffer the query is performed on, and second, an editor/view environment which determines the rules of interpretation. I am not certain, but I suspect that there will be reasons to implement multiple different environments, so there should probably be an Environment trait which each environment implements. The "SELECT" query, for example, could be interpreted in a certain environment with syntax highlighting, or without. Again, the environment and the target would be determined by the dispatching component from the query or some stored config information.
Currently, the file is written a line at a time. This is going to be problematic if the editor is killed mid-write, or some other process tries to write to the file at the same time. The usual solution to this (employed by vim, for example) is to create an exclusive temporary file, write to that, and then atomically replace the old file with it.
Currently there are just two unsafe blocks of code in the project. I'd like to remove them and only use safe code if possible.
I'm not sure if the current design will work without the unsafe code, though. Might be worth evaluating to see if its worth redesigning just to remove it.
At the moment, everything is drawn directly from the Buffer
structure to the UI. This means that we can only control parts of the terminal window which actually has some text in it.
For instance, for the status bar, I want to set the background to be a different colour. If the status bar is only 40 characters long, then I can only draw the different background for those 40 characters.
In order to be able to draw the full width of the terminal, there needs to be some kind of intermediate buffer which is filled with blank space characters, and which I can draw the Buffer
contents to. This then will be drawn to the terminal with rustbox.
This means that the status bar text can take up the first 40 characters, and the rest of the UIBuffer
blank content can make up the rest.
Doing this will also work well for creating a horizontal scroll, for lines which go wider than the terminal's width. The UIBuffer
can just display the line content which fits inside it, then only draw the rest when the cursor moves over it.
git pull
cargo build --release
./target/release/iota
and then
fish: Job 1, './target/release/iota ' terminated by signal SIGILL (Illegal instruction)
(I'm using the fish shell)
Support structural regexps.
I want to change Line
structure's data
attribute to be a a vector or array of char
s or u8
s. ie:
struct Line {
data: Vec<char>,
...
}
or
struct Line {
data: &[u8],
...
}
or
struct Line {
data: Vec<u8>,
...
}
I also want to change how files are read. Right now each file is read into a Vector of Strings, and then transferred to instances of Line
. I want to remove the use of Vec<String>
completely if possible.
Steps to reproduce:
./target/iota
delete
button)Note that there is no character in a clean file, so the editor shouldn't delete anything at all. But it panics instead.
View resizing doesn't work well, need to fix this before we can get split views working. This will involve changing how the status bar is drawn too.
Maybe adding a bottom_line
param to View
. Then draw the status bar after the end of the view.
Since gchp/rustbox#5 was merged, rustbox comes packaged with termbox so there are no additional installation steps required.
Applying the following changes
[dependencies]
-rustbox = "0.1.0"
docopt = "0.6.13"
+[dependencies.rustbox]
+git = "https://github.com/gchp/rustbox.git"
makes cargo build
the only required installation step.
A non exhaustive list of things I'd like to add to the editor.
Think lightweight vim. What I use most from vim is the movement commands, ie
h
, j
, k
, l
, w
, b
, e
.
The Acme editor stores its buffers as simple files in some far-off directory.
It would be cool if rdit could optionally create its buffers from some kind of
file somewhere on the OS.
for instance:
$ cat /opt/rdit/buffers/1
{active: true, path: /home/gchp/file.txt}
hello world
this is a text buffer
This indicates that the file in /opt/rdit/buffers/1
is the currently active
buffer, and the file linked to that buffer is file.txt
in my home directory.
This could also allow you to modify buffer contents from outside the editor. If
rdit is written to set buffer contents based on the files in /opt/rdit/buffers/*
then any editing tool could modify contents - sed for instance.
It would work well for the UNIX pipe integration too, possibly.
Not sure how much sense this makes just yet. Will need to read the ACME source
code a bit to find out how this really works.
This is not a Vim clone, however I'd like to implement some lightweight version of Vim's modal editing.
Modes to include:
I'll update this ticket as I go along and spec this out a bit more.
I'd like to relicense the project under the GPL.
Obviously, this would mean that code contributed already to this project under the MIT license would need to be relicensed. In order to do this I would like the contributors of said code permission to have their contributions relicensed.
If you've contributed code to Iota up to this point, can you comment below and let me know if you are happy for your contributions to be relicensed under the GPL. Alternatively, if you're not happy for this, please also comment below or email me (email address in commit log).
Thanks!
When you try to delete backwards from the end of a buffer, Iota will crash with the following error:
thread '<main>' panicked at 'index out of range', /home/gchp/.cargo/git/checkouts/gapbuffer-8b2fd52819acbe54/master/src/lib.rs:271
stack backtrace:
1: 0x7f19824fccd0 - sys::backtrace::write::hb7fa0f4f6b33ee3a8Rt
2: 0x7f19825001e0 - failure::on_fail::h4388493538a5ad8ck8z
3: 0x7f19824e90d0 - rt::unwind::begin_unwind_inner::h644ddf1c409df284cNz
4: 0x7f19824aea60 - rt::unwind::begin_unwind::h12738154783134983540
5: 0x7f19824c2170 - GapBuffer<T>::remove::h18422877085795087137
6: 0x7f19824c17b0 - buffer::Buffer::remove_chars::unboxed_closure.4893
7: 0x7f19824c16a0 - iter::FilterMap<A, B, I, F>.Iterator::next::h14431122262248638431
8: 0x7f19824c1620 - iter::Inspect<A, I, F>.Iterator::next::h16128471622825949221
9: 0x7f19824c15a0 - iter::Map<A, B, I, F>.Iterator::next::h10824938953637993840
10: 0x7f19824c12f0 - vec::Vec<T>.FromIterator<T>::from_iter::h5751581531197774384
11: 0x7f19824c1250 - iter::IteratorExt::collect::h17492329597111519392
12: 0x7f19824c0d00 - buffer::Buffer::remove_chars::h99717a5c0fab4d4brKa
13: 0x7f19824ccdd0 - view::View<'v>::delete_chars::h077bd7f050c8e641qUb
14: 0x7f19823f9090 - editor::Editor<'e, T>::handle_command::h9268632214995713731
15: 0x7f19823f38f0 - editor::Editor<'e, T>::handle_key_event::h9162057277965722021
16: 0x7f19823f0540 - editor::Editor<'e, T>::start::h10259774018777455307
17: 0x7f19823e04a0 - main::hf912c98fa0bf880cJda
18: 0x7f1982504e20 - rust_try_inner
19: 0x7f1982504e10 - rust_try
20: 0x7f1982501da0 - rt::lang_start::h46417f3fa3eb30a5w2z
21: 0x7f19823e0b50 - main
22: 0x7f19815e7a50 - __libc_start_main
23: 0x7f19823e0000 - <unknown>
24: 0x0 - <unknown>
An unknown error occurred
Seems as if the cursor position is one greater than the length of the buffer.
We will want to support a "read only" mode for this and avoid loading the entire file into memory. We will also want to do certain things asynchronously, like figure out line count, so as not to block editing. We may want to consider allowing asynchronous save as well (unfortunately, I don't think there's any way to significantly speed up saving a very large file in the general case, unless you get very lucky with block size and have control over the filesystem).
Opened by ./target/iota src/main.rs
and just did something like Pg-Down
, Pg-Down
, Enter
, Enter
, Pg-Down
, Pg-Down
Panick
task '<main>' panicked at 'index out of bounds: the len is 21 but the index is 21', src/iota/lib.rs:1
Options: task '<unnamed>' panicked at 'sending on a closed channel', /home/rustbuild/src/rust-buildbot/slave/nightly-linux/build/src/libstd/comm/mod.rs:555
";
Disclaimer: I'm new into Rust ecosystem, so I don't know what details to provide or how to obtain stacktrace et cetera ...
If anything I'm wiling to provide you with more details.
I put together a really rough version of a general purpose key binding system over here: https://github.com/Crespyl/iota/tree/keymap
I didn't think this version was really clean enough for a pull-request, but I'd be interested in feedback and thought there might be some interest.
Are there any existing plans/designs for handling Emacs style key sequences (C-x C-s
, C-u 10 C-x e
, etc.)? Has anyone already implemented this in a different or better way?
I got following error:
task '
' panicked at 'calledOption::unwrap()
on a None
value', /home/rustbuild/src/rust-buildbot/slave/nightly-linux/build/src/libcore/option.rs:360Right now we can only open the editor by opening an existing file. Need to be able to start both with an empty "untitled" buffer, and also one for a new file.
Travis is failing now because it can't find the termbox
library. Need to update the install script to install this before running the tests.
I’m not sure what the precise issue is, but loading UTF-8-encoded files with non-ASCII characters in them doesn’t work well. As a simple example, writing ÿ
to a file with a different editor and then loading that file with Iota shows garbled text.
in emacs or vi style.
Tested under ubuntu 14.10 inside virtualbox on windows 7
Build is failing right now on master on osx yosemite: rustc 0.13.0-nightly (ffc111889 2014-12-12 21:07:19 +0000)
src/iota/view.rs:183:25: 183:51 error: cannot infer an appropriate lifetime for lifetime parameter 'a in function call due to conflicting requirements
src/iota/view.rs:183 let line = &mut self.buffer.lines[linenum];
^~~~~~~~~~~~~~~~~~~~~~~~~~
src/iota/view.rs:182:5: 185:6 help: consider using an explicit lifetime parameter as shown: fn set_cursor_line(&'v mut self, linenum: uint)
src/iota/view.rs:182 fn set_cursor_line(&mut self, linenum: uint) {
src/iota/view.rs:183 let line = &mut self.buffer.lines[linenum];
src/iota/view.rs:184 self.cursor.set_line(Some(line));
src/iota/view.rs:185 }
Since #50 was merged, Unicode support is broken. @P1start mentioned in the comments that fixing this shouldn't be too involved.
Since the rustbox interaction was extracted to a frontend, it opens the door for implementing other frontends.
A possible frontend could be one using Conrod. This would be nice as it is also a pure rust implementation. Any other GUI would be cool though, as Conrod is pretty new and lacking some features we might need for this.
Frontends could be chosen at startup by a flag, or we could provide separate binaries for each frontend, like gvim and vim.
Support launching command and piping selected line/text through it (like sandy's Ctrl-| or sam | ‹command›
).
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.