Skip to content

Commit 5501811

Browse files
committed
Added VIM app
2 parents fff4dc1 + 4bd2a0f commit 5501811

File tree

630 files changed

+126493
-6
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

630 files changed

+126493
-6
lines changed

js/apps/vim/index.js

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
'use strict';
2+
3+
const Vim = require('./js-vim');
4+
let vim;
5+
let kb;
6+
let io;
7+
let res;
8+
// const tui = require('terminal-ui');
9+
10+
// const mauve = require('./mauve');
11+
// const scheme = require('./lib/scheme');
12+
// mauve.set(scheme);
13+
14+
const kbaliases = {
15+
enter: '\n',
16+
tab: '\t',
17+
backspace: '\b',
18+
space: ' ',
19+
escape: 'esc',
20+
kpup: '↑',
21+
kpdown: '↓',
22+
kpleft: '←',
23+
kpright: '→',
24+
};
25+
26+
// const kbignore = ['kpdown', 'kpup', 'kpleft', 'kpright'];
27+
28+
function keyboard(key) {
29+
if (key.type === 'kppagedown') {
30+
kb.onKeydown.remove(keyboard);
31+
return res(0);
32+
}
33+
34+
// if (kbignore.indexOf(key.type) !== -1) return false;
35+
if (key.type === 'character') {
36+
vim.exec(kbaliases[key.character] || key.character);
37+
} else {
38+
vim.exec(kbaliases[key.type] || key.type.slice(0, 2) === 'kp' ? '' : key.type);
39+
}
40+
return false;
41+
}
42+
43+
function main(api, cb) {
44+
// Instance
45+
vim = new Vim();
46+
47+
kb = api.keyboard;
48+
io = api.stdio;
49+
res = cb;
50+
51+
// Apply node commands (file write, etc.)
52+
require('./lib/commands')(vim);
53+
54+
kb.onKeydown.add(keyboard);
55+
56+
io.clear();
57+
io.write(vim.view.getText());
58+
59+
// Tie tui to vim.view
60+
vim.view.on('change', () => {
61+
io.clear();
62+
io.write(vim.view.getText());
63+
});
64+
}
65+
exports.commands = ['vim'];
66+
exports.call = (app, args, api, res) => {
67+
main(api, res);
68+
};

js/apps/vim/js-vim/.swo

12 KB
Binary file not shown.

js/apps/vim/js-vim/.travis.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
language: node_js
2+
node_js:
3+
- 0.10.5

js/apps/vim/js-vim/README.md

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#js-vim
2+
3+
![Build status](https://api.travis-ci.org/itsjoesullivan/js-vim.png)
4+
5+
A javascript implementation of the popular vi clone.
6+
7+
##Why bother?
8+
9+
We already edit a lot of code online. Bringing our editor of choice to the web makes that a more enjoyable process!
10+
11+
##Implementations
12+
13+
This repo contains the vim "model", which is currently implemented in [web-embeddable](https://github.com/itsjoesullivan/js-vim-embed/) and [terminal](https://github.com/itsjoesullivan/js-vim-node/) versions.
14+
15+
##Usage
16+
17+
What makes this project palatable is an extensible API:
18+
19+
```javascript
20+
vim.addCommand({
21+
mode: 'command',
22+
match: 'o',
23+
fn: function() {
24+
//The lowercase 'o' command can be represented using these commands
25+
this.exec(['$','a','\n']);
26+
}
27+
});
28+
```
29+
30+
Aside from simplifying the process of defining current vim commands, it makes extending vim a cinch:
31+
32+
```javascript
33+
//Open a file from dropbox
34+
vim.addCommand({
35+
mode: 'command',
36+
match: /:o (.*)\n/,
37+
fn: function(path) {
38+
dropboxClient.readFile(path, function(err,data) {
39+
if(err) return this.notify("Error reading file");
40+
var doc = new this.Doc({
41+
text: data,
42+
path: path
43+
});
44+
this.add(doc);
45+
});
46+
}
47+
});
48+
49+
//Save a file to dropbox
50+
vim.addCommand({
51+
mode: 'command',
52+
match: /:w(?: (.*))?\n/,
53+
fn: function(path) {
54+
var doc = this.curDoc,
55+
path = path || doc.path;
56+
dropboxClient.writeFile(path, doc.text(), function(err) {
57+
if(err) return this.notify(err);
58+
this.notify('"' + path + '" written.');
59+
});
60+
}
61+
});
62+
```
63+
64+
##License
65+
66+
The MIT License (MIT)
67+
68+
Copyright (c) 2013 Joe Sullivan
69+
70+
Permission is hereby granted, free of charge, to any person obtaining a copy
71+
of this software and associated documentation files (the "Software"), to deal
72+
in the Software without restriction, including without limitation the rights
73+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
74+
copies of the Software, and to permit persons to whom the Software is
75+
furnished to do so, subject to the following conditions:
76+
77+
The above copyright notice and this permission notice shall be included in
78+
all copies or substantial portions of the Software.
79+
80+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
81+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
82+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
83+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
84+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
85+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
86+
THE SOFTWARE.

js/apps/vim/js-vim/args.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#Why do this?
2+
3+
##vim-as-language
4+
One way to think of Vim is as a language: the language of navigating and editing a document.

js/apps/vim/js-vim/deploy

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
echo "Prepping js-vim-embed"
2+
cd ../js-vim-embed-page
3+
git checkout master
4+
echo " Building js-vim-embed"
5+
./build
6+
git add vim*
7+
git commit -m "js-vim update"
8+
echo " Committing new js-vim-embed"
9+
echo "Prepping js-vim-embed/gh-pages"
10+
git checkout gh-pages
11+
echo " Checking out new build"
12+
git checkout master vim.js
13+
git checkout master vim.min.js
14+
git add vim*
15+
echo " Committing changes"
16+
git commit -m "js-vim update"
17+
echo "Pushing to gh-pages"
18+
git push origin gh-pages
19+
echo "Deploy complete"

js/apps/vim/js-vim/design.md

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
##Explanation for the overall design
2+
3+
This is a slight elaboration of README for the sake of communicating the core of the design.
4+
5+
This project views vim's extensibility as arising from the interchangeability of various key commands:
6+
7+
```
8+
'2dd' --> 'dd', 'dd'
9+
10+
'dd' --> '0','v','$','x','del'
11+
```
12+
13+
So, if we define a few core commands:
14+
15+
```
16+
v: begin selection
17+
0: move to beginning of line
18+
$: move to end of line
19+
x: delete selection
20+
```
21+
22+
Then define a few other commands:
23+
24+
```
25+
'dd': ['0','v','$','x','del']
26+
'2dd': ['dd','dd']
27+
```
28+
29+
We start to get some of that extensibility.
30+
31+
###In code
32+
33+
If we implement commands as key/value pairs, where keys are regular expressions and values are functions:
34+
35+
```javascript
36+
/([0-9]+)dd/: function(result) { //result is /([0-9]+)dd/.exec(keyBuffer)
37+
vim.exec(['0','v']);
38+
var ct = parseInt(result[1]); //the captured number
39+
while(ct--) {
40+
vim.exec('j');
41+
}
42+
vim.exec(['$','x','backspace']);
43+
}
44+
```
45+
46+
We can be clever:
47+
48+
```javascript
49+
/dd/: function(result) {
50+
vim.exec('1dd');
51+
};
52+
```
53+
54+
###Command definition API
55+
56+
Commands depend on mode, so they are declared like:
57+
58+
```javascript
59+
vim.addMode({
60+
'insert': {
61+
'(.*)': function(res) {
62+
vim.insert(res[0]);
63+
}
64+
}
65+
});
66+
67+
vim.addMode({
68+
'command': {
69+
'i': function() {
70+
vim.mode = 'insert';
71+
},
72+
'j': function(res) {
73+
vim.cursor.line--;
74+
},
75+
...
76+
}
77+
});
78+
```
79+
80+
###Useful functionality
81+
82+
Any key combination can take advantage of the others, but they can do whatever they want. Looking down the road a bit:
83+
84+
```javascript
85+
// /src/modes/github.js
86+
87+
//imagine this exists, which it kind of does.
88+
var git = new Github({username: cred.username, password: cred.password});
89+
var repo = git.getRepo('itsjoesullivan/vim');
90+
91+
vim.fileSystem.addDirectory('itsjoesullivan/vim',repo.ls()); //maybe we could add a filesystem here
92+
93+
/*
94+
now:
95+
vim.exec(':cd itsjoesullivan/vim'); //imagine this exists
96+
vim.exec(':e index.html'); //opens file at https://github.com/itsjoesullivan/vim/index.html
97+
*/
98+
99+
vim.addMode({
100+
'github': {
101+
/gh push/: function(res) {
102+
repo.push(); //imagining we've connected to github, the document came from there, whatever.
103+
},
104+
/gh add (.*)/: function(res) {
105+
repo.add(res[1]); //let git handle "index.*" vs "index.html"
106+
},
107+
/gh commit (.*)/: function(res) {
108+
repo.commit(res[1]); //similar.
109+
}
110+
}
111+
});
112+
```
113+
114+
###Testing
115+
116+
Testing of key operations is very straightforward:
117+
118+
```javascript
119+
describe('command::x', function() {
120+
it('erases current character', function() {
121+
vim.doc.set('hello\nworld');
122+
vim.exec(['gg','x']);
123+
expect(vim.doc.get()).equal('ello\nworld');
124+
});
125+
});
126+
```
127+
128+
###Rendering
129+
130+
One reason that vim as a web app is cool is because, from a rendering perspective, it's very simple (it runs on old computers!), so it's a good way begin to create an "app" feel in the browser. However, for that reason, it deviates a lot from the DOM paradigm. For example, semantic html would put the entire application into a \<textarea>. Needless to say, that's not helpful. A Backbone-oriented MV system puts each character in its own view (\<span class='char'>h\</span>), which again is not terrifically helpful. A rendering framework that takes some of the manual rendering work out of, say, changing the 'function' keyword a certain color for the sake of syntax highlighting, would be welcome in this project.
131+
132+
###Other stuff
133+
134+
There are other dimensions to vim than text editing: syntax highlighting; formatting; plugins; ... . Those dimensions can largely be implemented alongside the above syntax. The above architecture says nothing about document structure, and it's possible to define such structure in a custom mode, though likely that's better defined at a lower level along with rendering logic. The main point is that the above design allows most development to occur at a relatively high level that's roughly the equivalent of key commands. Only a handful of operations (search, delete, insert, select, move, copy) need to operate on the application internals / document structure.

js/apps/vim/js-vim/docs/Cursor.md

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#Cursor
2+
3+
Each doc has at least one cursor. It represents... well, you know.
4+
5+
##API
6+
7+
###Cursor.line(lineNumber)
8+
9+
Get / set the cursor's line number.
10+
11+
__N.B.__ As everywhere else, line number is zero-indexed.
12+
13+
####Get
14+
```javascript
15+
var line = cursor.line();
16+
console.log("The current line number is: " + line);
17+
```
18+
####Set
19+
```javascript
20+
cursor.line(10);
21+
```
22+
###Cursor.char(charNumber)
23+
24+
Get / set the cursor's character.
25+
26+
__N.B.__ This should be changed to "col"
27+
28+
__N.B.__ As everywhere else, line number is zero-indexed.
29+
30+
####Get
31+
32+
```javascript
33+
var col = cursor.char();
34+
console.log("The current column is: " + col);
35+
```
36+
37+
####Set
38+
39+
```javascript
40+
cursor.char(10);
41+
```
42+
43+
###Cursor.col(colNumber)
44+
45+
Alias for cursor.char
46+
47+
###Cursor.position(pos)
48+
49+
Get / set the overall cursor position... syntactic sugar for setting line and char/col individually
50+
51+
####Returns:
52+
```javascript
53+
{
54+
line: {Number},
55+
char: {Number}
56+
}
57+
```
58+
59+
####Get
60+
61+
```javascript
62+
var pos = cursor.position();
63+
```
64+
65+
####Set
66+
```javascript
67+
var pos = {
68+
line: 2,
69+
char: 4
70+
}
71+
cursor.position(pos);
72+
```

0 commit comments

Comments
 (0)