Skip to content

Commit 3240227

Browse files
committed
feature(vim) add hot keys
1 parent dc79ab4 commit 3240227

File tree

13 files changed

+649
-21
lines changed

13 files changed

+649
-21
lines changed

HELP.md

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,18 +89,20 @@ Cloud Commander supports command line parameters:
8989
| `--console` | enable console
9090
| `--terminal` | enable terminal
9191
| `--terminal-path` | set terminal path
92+
| `--vim` | enable vim hot keys
9293
| `--no-server` | do not start server
9394
| `--no-auth` | disable authorization
9495
| `--no-online` | load scripts from local server
9596
| `--no-open` | do not open web browser when server started
97+
| `--no-name` | set empty tab name in web browser
98+
| `--no-one-panel-mode` | unset one panel mode
9699
| `--no-progress` | do not show progress of file operations
97100
| `--no-html-dialogs` | do not use html dialogs
98-
| `--no-one-panel-mode` | unset one panel mode
99101
| `--no-contact` | disable contact
100102
| `--no-config-dialog` | disable config dialog
101103
| `--no-console` | disable console
102104
| `--no-terminal` | disable terminal
103-
| `--no-name` | set empty tab name in web browser
105+
| `--no-vim` | disable vim hot keys
104106

105107

106108
If no parameters given Cloud Commander reads information from `~/.cloudcmd.json` and use
@@ -174,6 +176,27 @@ Hot keys
174176
| `~` | console
175177
| `Ctrl + Click` | open file on new tab
176178

179+
### Vim
180+
181+
When `--vim` option provided, or configuration parameter `vim` set, next hot keys become available:
182+
183+
|Key |Operation
184+
|:----------------------|:--------------------------------------------
185+
| `j` | navigate to next file
186+
| `k` | navigate to previous file
187+
| `dd` | remove current file
188+
| `G` | navigate to bottom file
189+
| `gg` | navigate to top file
190+
| `v` | visual mode
191+
| `y` | copy (selected in visual mode files)
192+
| `p` | paste files
193+
| `Esc` | unselect all
194+
195+
Commands can be joined, for example:
196+
- `5j` will navigate `5` files below current;
197+
- `d5j` will remove next `5` files;
198+
- `dG` will remove all files from current to bottom;
199+
177200
View
178201
---------------
179202
![View](/img/screen/view.png "View")
@@ -333,6 +356,7 @@ Here is description of options:
333356
"console" : true, /* enable console */
334357
"terminal" : false, /* disable terminal */
335358
"terminalPath" : '', /* path of a terminal */
359+
"vim" : false, /* disable vim hot keys */
336360
}
337361
```
338362

client/dom/index.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,14 @@ function CmdProto() {
533533
return Cmd;
534534
};
535535

536+
this.unselectFile = (currentFile) => {
537+
const current = currentFile || DOM.getCurrentFile();
538+
539+
current.classList.remove(SELECTED_FILE);
540+
541+
return Cmd;
542+
};
543+
536544
this.toggleSelectedFile = (currentFile) => {
537545
const current = currentFile || DOM.getCurrentFile();
538546
const name = DOM.getCurrentName(current);

client/key/index.js

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const exec = require('execon');
99
const Events = require('../dom/events');
1010
const Buffer = require('../dom/buffer');
1111
const KEY = require('./key');
12+
const vim = require('./vim');
1213
const setCurrentByChar = require('./set-current-by-char');
1314
const fullstore = require('fullstore/legacy');
1415
const Chars = fullstore();
@@ -71,15 +72,19 @@ function KeyProto() {
7172
char = isSymbol;
7273
}
7374

74-
/* in case buttons can be processed */
7575
if (!Key.isBind())
7676
return;
7777

78-
if (!isNumpad && !alt && !ctrl && !meta && (isBetween || isSymbol))
78+
const isVim = CloudCmd.config('vim');
79+
80+
if (!isVim && !isNumpad && !alt && !ctrl && !meta && (isBetween || isSymbol))
7981
return setCurrentByChar(char, Chars);
8082

8183
Chars([]);
8284
switchKey(event);
85+
86+
if (isVim)
87+
vim(char, event);
8388
}
8489

8590
function getSymbol(shift, keyCode) {
@@ -106,6 +111,8 @@ function KeyProto() {
106111
function switchKey(event) {
107112
let i, isSelected, prev, next;
108113
let current = Info.element;
114+
let dataName;
115+
109116
const name = Info.name;
110117

111118
const {Operation} = CloudCmd;
@@ -301,9 +308,9 @@ function KeyProto() {
301308

302309
event.preventDefault();
303310

304-
const attr = Info.panel.getAttribute('data-name');
311+
dataName = Info.panel.getAttribute('data-name');
305312

306-
if (attr === 'js-right')
313+
if (dataName === 'js-right')
307314
DOM.duplicatePanel();
308315

309316
break;
@@ -314,9 +321,9 @@ function KeyProto() {
314321

315322
event.preventDefault();
316323

317-
name = Info.panel.getAttribute('data-name');
324+
dataName = Info.panel.getAttribute('data-name');
318325

319-
if (name === 'js-left')
326+
if (dataName === 'js-left')
320327
DOM.duplicatePanel();
321328

322329
break;

client/key/key.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
'use strict';
2+
13
module.exports = {
24
BACKSPACE : 8,
35
TAB : 9,
@@ -20,13 +22,20 @@ module.exports = {
2022

2123
ZERO : 48,
2224

25+
SEMICOLON : 52,
26+
27+
COLON : 54,
28+
2329
A : 65,
2430

2531
C : 67,
2632
D : 68,
2733

2834
G : 71,
2935

36+
J : 74,
37+
K : 75,
38+
3039
M : 77,
3140

3241
O : 79,

client/key/set-current-by-char.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
'use strict';
44

55
const Info = DOM.CurrentInfo;
6-
76
const {escapeRegExp} = require('../../common/util');
87

98
module.exports = function setCurrentByChar(char, charStore) {
@@ -56,5 +55,5 @@ module.exports = function setCurrentByChar(char, charStore) {
5655
DOM.setCurrentFile(firstByName);
5756
charStore([char]);
5857
}
59-
}
58+
};
6059

client/key/vim.js

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
'use strict';
2+
/* global CloudCmd, DOM */
3+
4+
const Info = DOM.CurrentInfo;
5+
const KEY = require('./key');
6+
7+
const fullstore = require('fullstore/legacy');
8+
const store = fullstore('');
9+
const visual = fullstore(false);
10+
11+
const stopVisual = () => {
12+
visual(false);
13+
};
14+
15+
const end = () => {
16+
store('');
17+
};
18+
19+
const rmFirst = (a) => {
20+
return a
21+
.split('')
22+
.slice(1)
23+
.join('');
24+
};
25+
26+
module.exports = (key, event) => {
27+
const current = Info.element;
28+
const keyCode = event.keyCode;
29+
const prevStore = store();
30+
31+
const value = store(prevStore.concat(key));
32+
33+
if (keyCode === KEY.ENTER)
34+
return end();
35+
36+
if (keyCode === KEY.ESC) {
37+
DOM.unselectFiles();
38+
visual(false);
39+
return end();
40+
}
41+
42+
if (key === 'j') {
43+
move('next', {
44+
prevStore,
45+
current,
46+
});
47+
48+
return end();
49+
}
50+
51+
if (key === 'k') {
52+
move('previous', {
53+
prevStore,
54+
current,
55+
});
56+
57+
return end();
58+
}
59+
60+
if (/gg/.test(value)) {
61+
move('previous', {
62+
current,
63+
prevStore,
64+
max: Infinity,
65+
});
66+
67+
return end();
68+
}
69+
70+
if (key === 'd' && (visual() || prevStore === 'd')) {
71+
CloudCmd.Operation.show('delete');
72+
stopVisual();
73+
return end();
74+
}
75+
76+
if (key === 'G') {
77+
move('next', {
78+
current,
79+
prevStore,
80+
max: Infinity,
81+
});
82+
83+
return end();
84+
}
85+
86+
if (key === 'y') {
87+
if (!visual())
88+
return end();
89+
90+
DOM.Buffer.copy();
91+
stopVisual();
92+
DOM.unselectFiles();
93+
return end();
94+
}
95+
96+
if (/^p$/i.test(key)) {
97+
DOM.Buffer.paste();
98+
return end();
99+
}
100+
101+
if (/^v$/i.test(key)) {
102+
DOM.toggleSelectedFile(current);
103+
visual(!visual());
104+
105+
return end();
106+
}
107+
};
108+
109+
module.exports.selectFile = selectFile;
110+
111+
function move(sibling, {max, current, prevStore}) {
112+
const isDelete = prevStore[0] === 'd';
113+
114+
if (isDelete) {
115+
visual(true);
116+
prevStore = rmFirst(prevStore);
117+
}
118+
119+
const n = max || getNumber(prevStore);
120+
121+
if (isNaN(n))
122+
return;
123+
124+
setCurrent({
125+
n,
126+
current,
127+
sibling,
128+
visual: visual(),
129+
});
130+
131+
if (isDelete)
132+
CloudCmd.Operation.show('delete');
133+
}
134+
135+
function getNumber(value) {
136+
if (!value)
137+
return 1;
138+
139+
if (value === 'g')
140+
return 1;
141+
142+
return parseInt(value);
143+
}
144+
145+
function selectFile(current) {
146+
const name = DOM.getCurrentName(current);
147+
148+
if (name === '..')
149+
return;
150+
151+
DOM.selectFile(current);
152+
}
153+
154+
function setCurrent({n, current, visual, sibling}) {
155+
const select = visual ? selectFile : DOM.unselectFile;
156+
157+
select(current);
158+
159+
const position = `${sibling}Sibling`;
160+
for (let i = 0; i < n; i++) {
161+
const next = current[position];
162+
163+
if (!next)
164+
break;
165+
166+
current = next;
167+
select(current);
168+
}
169+
170+
DOM.setCurrentFile(current);
171+
}
172+

img/screen/config.png

-1.02 KB
Loading

json/config.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"console": true,
2828
"terminal": false,
2929
"terminalPath": "",
30-
"showConfig": "false"
30+
"showConfig": "false",
31+
"vim": "true"
3132
}
3233

json/help.json

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,26 @@
1515
"--port ": "set port number",
1616
"--progress ": "show progress of file operations",
1717
"--html-dialogs ": "use html dialogs",
18+
"--open ": "open web browser when server started",
19+
"--name ": "set tab name in web browser",
1820
"--one-panel-mode ": "set one panel mode",
1921
"--config-dialog ": "enable config dialog",
2022
"--console ": "enable console",
2123
"--contact ": "enable contact",
2224
"--terminal ": "enable terminal",
2325
"--terminal-path ": "set terminal path",
24-
"--open ": "open web browser when server started",
25-
"--name ": "set tab name in web browser",
26+
"--vim ": "enable vim hot keys",
2627
"--no-server ": "do not start server",
2728
"--no-auth ": "disable authorization",
2829
"--no-online ": "load scripts from local server",
2930
"--no-open ": "do not open web browser when server started",
31+
"--no-name ": "set default tab name in web browser",
32+
"--no-one-panel-mode ": "unset one panel mode",
3033
"--no-progress ": "do not show progress of file operations",
3134
"--no-html-dialogs ": "do not use html dialogs",
32-
"--no-one-panel-mode ": "unset one panel mode",
3335
"--no-config-dialog ": "disable config dialog",
3436
"--no-console ": "disable console",
3537
"--no-contact ": "disable contact",
3638
"--no-terminal ": "disable terminal",
37-
"--no-name ": "set default tab name in web browser"
39+
"--no-vim ": "disable vim hot keys"
3840
}

0 commit comments

Comments
 (0)