dirvi-lib 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/application/intent-to-effect-no-state.test.d.ts +2 -0
- package/dist/application/intent-to-effect-no-state.test.d.ts.map +1 -0
- package/dist/application/intent-to-effect-no-state.test.js +178 -0
- package/dist/application/intent-to-effect.d.ts +8 -0
- package/dist/application/intent-to-effect.d.ts.map +1 -0
- package/dist/application/intent-to-effect.js +142 -0
- package/dist/application/intent-to-effect.test-no-state.d.ts +2 -0
- package/dist/application/intent-to-effect.test-no-state.d.ts.map +1 -0
- package/dist/application/intent-to-effect.test-no-state.js +178 -0
- package/dist/application/user-input-to-intent.d.ts +8 -0
- package/dist/application/user-input-to-intent.d.ts.map +1 -0
- package/dist/application/user-input-to-intent.js +98 -0
- package/dist/application/user-input-to-intent.test.d.ts +2 -0
- package/dist/application/user-input-to-intent.test.d.ts.map +1 -0
- package/dist/application/user-input-to-intent.test.js +125 -0
- package/dist/domain/cursor.d.ts +15 -13
- package/dist/domain/cursor.js +43 -41
- package/dist/domain/display-row.d.ts +28 -23
- package/dist/domain/display-row.d.ts.map +1 -1
- package/dist/domain/display-row.js +26 -22
- package/dist/domain/effect.d.ts +48 -0
- package/dist/domain/effect.d.ts.map +1 -0
- package/dist/domain/effect.js +1 -0
- package/dist/domain/fold-node.d.ts +20 -12
- package/dist/domain/fold-node.js +82 -70
- package/dist/domain/input-state.d.ts +10 -0
- package/dist/domain/input-state.d.ts.map +1 -0
- package/dist/domain/input-state.js +1 -0
- package/dist/domain/intent.d.ts +34 -0
- package/dist/domain/intent.d.ts.map +1 -0
- package/dist/domain/intent.js +1 -0
- package/dist/domain/navigation-node.d.ts +47 -32
- package/dist/domain/navigation-node.js +201 -189
- package/dist/domain/state.d.ts +5 -5
- package/dist/domain/state.d.ts.map +1 -1
- package/dist/domain/state.js +7 -7
- package/dist/domain/unix-entry.d.ts +35 -19
- package/dist/domain/unix-entry.d.ts.map +1 -1
- package/dist/domain/unix-entry.js +94 -82
- package/dist/domain/unix-path.d.ts +1 -1
- package/dist/domain/unix-path.js +9 -6
- package/dist/domain/user-input.d.ts +27 -0
- package/dist/domain/user-input.d.ts.map +1 -0
- package/dist/domain/user-input.js +1 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/infrastructure/get-cwd.d.ts +1 -1
- package/dist/infrastructure/get-cwd.js +12 -10
- package/dist/infrastructure/get-dir-lazy-entries.d.ts +4 -2
- package/dist/infrastructure/get-dir-lazy-entries.js +34 -28
- package/package.json +4 -2
- package/dist/domain/fold.d.ts +0 -10
- package/dist/domain/fold.d.ts.map +0 -1
- package/dist/domain/fold.js +0 -24
- package/dist/domain/navigation-entry.d.ts +0 -23
- package/dist/domain/navigation-entry.d.ts.map +0 -1
- package/dist/domain/navigation-entry.js +0 -52
- package/dist/domain/view.d.ts +0 -15
- package/dist/domain/view.d.ts.map +0 -1
- package/dist/domain/view.js +0 -12
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intent-to-effect-no-state.test.d.ts","sourceRoot":"","sources":["../../src/application/intent-to-effect-no-state.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { intentToEffect } from './intent-to-effect.js';
|
|
3
|
+
const state = {};
|
|
4
|
+
describe('intentToEffectNoState', () => {
|
|
5
|
+
describe('normal mode buffer', () => {
|
|
6
|
+
it('stores z as a possible command prefix', () => {
|
|
7
|
+
expect(
|
|
8
|
+
intentToEffect(
|
|
9
|
+
{
|
|
10
|
+
intentType: 'setNormalBuffer',
|
|
11
|
+
normalBuffer: 'z',
|
|
12
|
+
},
|
|
13
|
+
state,
|
|
14
|
+
),
|
|
15
|
+
).toEqual({
|
|
16
|
+
effectType: 'setInputState',
|
|
17
|
+
inputState: {
|
|
18
|
+
inputMode: 'normal',
|
|
19
|
+
normalBuffer: 'z',
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
it.each([
|
|
24
|
+
['za', 'toggleFold'],
|
|
25
|
+
['zc', 'fold'],
|
|
26
|
+
['zo', 'unfold'],
|
|
27
|
+
])(
|
|
28
|
+
'converts %s into a %s effect action',
|
|
29
|
+
(normalBuffer, effectActionType) => {
|
|
30
|
+
expect(
|
|
31
|
+
intentToEffect(
|
|
32
|
+
{
|
|
33
|
+
intentType: 'setNormalBuffer',
|
|
34
|
+
normalBuffer,
|
|
35
|
+
},
|
|
36
|
+
state,
|
|
37
|
+
),
|
|
38
|
+
).toEqual({
|
|
39
|
+
effectType: 'dispatchEffectAction',
|
|
40
|
+
action: {
|
|
41
|
+
effectActionType,
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
},
|
|
45
|
+
);
|
|
46
|
+
it('clears the normal buffer when the input is not a known command', () => {
|
|
47
|
+
expect(
|
|
48
|
+
intentToEffect(
|
|
49
|
+
{
|
|
50
|
+
intentType: 'setNormalBuffer',
|
|
51
|
+
normalBuffer: 'x',
|
|
52
|
+
},
|
|
53
|
+
state,
|
|
54
|
+
),
|
|
55
|
+
).toEqual({
|
|
56
|
+
effectType: 'setInputState',
|
|
57
|
+
inputState: {
|
|
58
|
+
inputMode: 'normal',
|
|
59
|
+
normalBuffer: '',
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
describe('normal mode navigation', () => {
|
|
65
|
+
it('moves to the next entry', () => {
|
|
66
|
+
expect(
|
|
67
|
+
intentToEffect(
|
|
68
|
+
{
|
|
69
|
+
intentType: 'normalDown',
|
|
70
|
+
},
|
|
71
|
+
state,
|
|
72
|
+
),
|
|
73
|
+
).toEqual({
|
|
74
|
+
effectType: 'dispatchEffectAction',
|
|
75
|
+
action: {
|
|
76
|
+
effectActionType: 'nextEntry',
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
it('moves to the previous entry', () => {
|
|
81
|
+
expect(
|
|
82
|
+
intentToEffect(
|
|
83
|
+
{
|
|
84
|
+
intentType: 'normalUp',
|
|
85
|
+
},
|
|
86
|
+
state,
|
|
87
|
+
),
|
|
88
|
+
).toEqual({
|
|
89
|
+
effectType: 'dispatchEffectAction',
|
|
90
|
+
action: {
|
|
91
|
+
effectActionType: 'prevEntry',
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
describe('command-line mode', () => {
|
|
97
|
+
it('enters command-line mode', () => {
|
|
98
|
+
expect(
|
|
99
|
+
intentToEffect(
|
|
100
|
+
{
|
|
101
|
+
intentType: 'enterCommandLineMode',
|
|
102
|
+
},
|
|
103
|
+
state,
|
|
104
|
+
),
|
|
105
|
+
).toEqual({
|
|
106
|
+
effectType: 'setInputState',
|
|
107
|
+
inputState: {
|
|
108
|
+
inputMode: 'command',
|
|
109
|
+
commandLine: ':',
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
it('updates the command line', () => {
|
|
114
|
+
expect(
|
|
115
|
+
intentToEffect(
|
|
116
|
+
{
|
|
117
|
+
intentType: 'setCommandLine',
|
|
118
|
+
commandLine: ':w',
|
|
119
|
+
},
|
|
120
|
+
state,
|
|
121
|
+
),
|
|
122
|
+
).toEqual({
|
|
123
|
+
effectType: 'setInputState',
|
|
124
|
+
inputState: {
|
|
125
|
+
inputMode: 'command',
|
|
126
|
+
commandLine: ':w',
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
it('exits command-line mode', () => {
|
|
131
|
+
expect(
|
|
132
|
+
intentToEffect(
|
|
133
|
+
{
|
|
134
|
+
intentType: 'exitCommandLineMode',
|
|
135
|
+
},
|
|
136
|
+
state,
|
|
137
|
+
),
|
|
138
|
+
).toEqual({
|
|
139
|
+
effectType: 'setInputState',
|
|
140
|
+
inputState: {
|
|
141
|
+
inputMode: 'normal',
|
|
142
|
+
normalBuffer: '',
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
it('returns to normal mode after executing a gibberish command line', () => {
|
|
147
|
+
expect(
|
|
148
|
+
intentToEffect(
|
|
149
|
+
{
|
|
150
|
+
intentType: 'executeCommandLine',
|
|
151
|
+
commandLine: ':sijbas',
|
|
152
|
+
},
|
|
153
|
+
state,
|
|
154
|
+
),
|
|
155
|
+
).toEqual({
|
|
156
|
+
effectType: 'setInputState',
|
|
157
|
+
inputState: {
|
|
158
|
+
inputMode: 'normal',
|
|
159
|
+
normalBuffer: '',
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
it('quits when the :q command is executed', () => {
|
|
164
|
+
expect(
|
|
165
|
+
intentToEffect(
|
|
166
|
+
{
|
|
167
|
+
intentType: 'executeCommandLine',
|
|
168
|
+
commandLine: ':q',
|
|
169
|
+
},
|
|
170
|
+
state,
|
|
171
|
+
),
|
|
172
|
+
).toEqual({
|
|
173
|
+
effectType: 'quit',
|
|
174
|
+
exitMessage: '',
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Effect } from '../domain/effect.js';
|
|
2
|
+
import { State } from '../domain/state.js';
|
|
3
|
+
import { Intent } from '../domain/intent.js';
|
|
4
|
+
export declare function intentToEffect(
|
|
5
|
+
intent: Intent,
|
|
6
|
+
state: State,
|
|
7
|
+
): Effect | undefined;
|
|
8
|
+
//# sourceMappingURL=intent-to-effect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intent-to-effect.d.ts","sourceRoot":"","sources":["../../src/application/intent-to-effect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAgB,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,KAAK,EAAQ,MAAM,oBAAoB,CAAC;AAEjD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAU7C,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,KAAK,GACX,MAAM,GAAG,SAAS,CAgEpB"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { View } from '../domain/state.js';
|
|
2
|
+
import { Cursor } from '../domain/cursor.js';
|
|
3
|
+
function dispatchAction(action) {
|
|
4
|
+
return {
|
|
5
|
+
effectType: 'dispatchEffectAction',
|
|
6
|
+
action,
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
// Effect derived from intent and the state.
|
|
10
|
+
export function intentToEffect(intent, state) {
|
|
11
|
+
switch (intent.intentType) {
|
|
12
|
+
case 'setNormalBuffer':
|
|
13
|
+
return normalBufferToEffectResult(intent.normalBuffer);
|
|
14
|
+
case 'normalRight':
|
|
15
|
+
return normalInteractRightToEffect(state);
|
|
16
|
+
case 'normalLeft':
|
|
17
|
+
return normalInteractLeftToEffect(state);
|
|
18
|
+
case 'normalDown':
|
|
19
|
+
return dispatchAction({
|
|
20
|
+
effectActionType: 'nextEntry',
|
|
21
|
+
});
|
|
22
|
+
case 'normalUp':
|
|
23
|
+
return dispatchAction({
|
|
24
|
+
effectActionType: 'prevEntry',
|
|
25
|
+
});
|
|
26
|
+
case 'enterCommandLineMode':
|
|
27
|
+
return {
|
|
28
|
+
effectType: 'setInputState',
|
|
29
|
+
inputState: {
|
|
30
|
+
inputMode: 'command',
|
|
31
|
+
commandLine: ':',
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
case 'setCommandLine':
|
|
35
|
+
return {
|
|
36
|
+
effectType: 'setInputState',
|
|
37
|
+
inputState: {
|
|
38
|
+
inputMode: 'command',
|
|
39
|
+
commandLine: intent.commandLine,
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
case 'exitCommandLineMode':
|
|
43
|
+
return {
|
|
44
|
+
effectType: 'setInputState',
|
|
45
|
+
inputState: {
|
|
46
|
+
inputMode: 'normal',
|
|
47
|
+
normalBuffer: '',
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
case 'executeCommandLine':
|
|
51
|
+
if (intent.commandLine === ':q') {
|
|
52
|
+
return {
|
|
53
|
+
effectType: 'quit',
|
|
54
|
+
exitMessage: '',
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
effectType: 'setInputState',
|
|
59
|
+
inputState: {
|
|
60
|
+
inputMode: 'normal',
|
|
61
|
+
normalBuffer: '',
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// Sets the buffer. Three possibilities:
|
|
67
|
+
// - New command buffer is recognized as a motion, this dispatches the
|
|
68
|
+
// "effect action". Consumer will know to reset the input state.
|
|
69
|
+
// - Prefix of a possible motion, updates normal buffer.
|
|
70
|
+
// - Not a prefix, clears the buffer.
|
|
71
|
+
function normalBufferToEffectResult(updatedNormalBuffer) {
|
|
72
|
+
switch (updatedNormalBuffer) {
|
|
73
|
+
case 'z':
|
|
74
|
+
return {
|
|
75
|
+
effectType: 'setInputState',
|
|
76
|
+
inputState: {
|
|
77
|
+
inputMode: 'normal',
|
|
78
|
+
normalBuffer: updatedNormalBuffer,
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
case 'za':
|
|
82
|
+
return dispatchAction({
|
|
83
|
+
effectActionType: 'toggleFold',
|
|
84
|
+
});
|
|
85
|
+
case 'zc':
|
|
86
|
+
return dispatchAction({
|
|
87
|
+
effectActionType: 'fold',
|
|
88
|
+
});
|
|
89
|
+
case 'zo':
|
|
90
|
+
return dispatchAction({
|
|
91
|
+
effectActionType: 'unfold',
|
|
92
|
+
});
|
|
93
|
+
default:
|
|
94
|
+
return {
|
|
95
|
+
effectType: 'setInputState',
|
|
96
|
+
inputState: {
|
|
97
|
+
inputMode: 'normal',
|
|
98
|
+
normalBuffer: '',
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function normalInteractRightToEffect(state) {
|
|
104
|
+
const currentEntry = View.getEntryAtCursor(state);
|
|
105
|
+
if (currentEntry === undefined) {
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
108
|
+
const path = Cursor.getPath(state.cursor);
|
|
109
|
+
if (path === undefined) {
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
if (currentEntry.kind === 'directory') {
|
|
113
|
+
if (currentEntry.entries === undefined) {
|
|
114
|
+
return {
|
|
115
|
+
effectType: 'loadDir',
|
|
116
|
+
path,
|
|
117
|
+
};
|
|
118
|
+
} else {
|
|
119
|
+
return dispatchAction({
|
|
120
|
+
effectActionType: 'updateDir',
|
|
121
|
+
path,
|
|
122
|
+
entries: undefined,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (currentEntry.kind === 'file') {
|
|
127
|
+
return {
|
|
128
|
+
effectType: 'printFile',
|
|
129
|
+
path,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
// TODO Later: Peeking on folds
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
function normalInteractLeftToEffect(state) {
|
|
136
|
+
if (state.cursor.parentPath.length === 0) {
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
139
|
+
return dispatchAction({
|
|
140
|
+
effectActionType: 'outDir',
|
|
141
|
+
});
|
|
142
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intent-to-effect.test-no-state.d.ts","sourceRoot":"","sources":["../../src/application/intent-to-effect.test-no-state.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { intentToEffect } from './intent-to-effect.js';
|
|
3
|
+
const state = {};
|
|
4
|
+
describe('intentToEffectNoState', () => {
|
|
5
|
+
describe('normal mode buffer', () => {
|
|
6
|
+
it('stores z as a possible command prefix', () => {
|
|
7
|
+
expect(
|
|
8
|
+
intentToEffect(
|
|
9
|
+
{
|
|
10
|
+
intentType: 'setNormalBuffer',
|
|
11
|
+
normalBuffer: 'z',
|
|
12
|
+
},
|
|
13
|
+
state,
|
|
14
|
+
),
|
|
15
|
+
).toEqual({
|
|
16
|
+
effectType: 'setInputState',
|
|
17
|
+
inputState: {
|
|
18
|
+
inputMode: 'normal',
|
|
19
|
+
normalBuffer: 'z',
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
it.each([
|
|
24
|
+
['za', 'toggleFold'],
|
|
25
|
+
['zc', 'fold'],
|
|
26
|
+
['zo', 'unfold'],
|
|
27
|
+
])(
|
|
28
|
+
'converts %s into a %s effect action',
|
|
29
|
+
(normalBuffer, effectActionType) => {
|
|
30
|
+
expect(
|
|
31
|
+
intentToEffect(
|
|
32
|
+
{
|
|
33
|
+
intentType: 'setNormalBuffer',
|
|
34
|
+
normalBuffer,
|
|
35
|
+
},
|
|
36
|
+
state,
|
|
37
|
+
),
|
|
38
|
+
).toEqual({
|
|
39
|
+
effectType: 'dispatchEffectAction',
|
|
40
|
+
action: {
|
|
41
|
+
effectActionType,
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
},
|
|
45
|
+
);
|
|
46
|
+
it('clears the normal buffer when the input is not a known command', () => {
|
|
47
|
+
expect(
|
|
48
|
+
intentToEffect(
|
|
49
|
+
{
|
|
50
|
+
intentType: 'setNormalBuffer',
|
|
51
|
+
normalBuffer: 'x',
|
|
52
|
+
},
|
|
53
|
+
state,
|
|
54
|
+
),
|
|
55
|
+
).toEqual({
|
|
56
|
+
effectType: 'setInputState',
|
|
57
|
+
inputState: {
|
|
58
|
+
inputMode: 'normal',
|
|
59
|
+
normalBuffer: '',
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
describe('normal mode navigation', () => {
|
|
65
|
+
it('moves to the next entry', () => {
|
|
66
|
+
expect(
|
|
67
|
+
intentToEffect(
|
|
68
|
+
{
|
|
69
|
+
intentType: 'normalDown',
|
|
70
|
+
},
|
|
71
|
+
state,
|
|
72
|
+
),
|
|
73
|
+
).toEqual({
|
|
74
|
+
effectType: 'dispatchEffectAction',
|
|
75
|
+
action: {
|
|
76
|
+
effectActionType: 'nextEntry',
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
it('moves to the previous entry', () => {
|
|
81
|
+
expect(
|
|
82
|
+
intentToEffect(
|
|
83
|
+
{
|
|
84
|
+
intentType: 'normalUp',
|
|
85
|
+
},
|
|
86
|
+
state,
|
|
87
|
+
),
|
|
88
|
+
).toEqual({
|
|
89
|
+
effectType: 'dispatchEffectAction',
|
|
90
|
+
action: {
|
|
91
|
+
effectActionType: 'prevEntry',
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
describe('command-line mode', () => {
|
|
97
|
+
it('enters command-line mode', () => {
|
|
98
|
+
expect(
|
|
99
|
+
intentToEffect(
|
|
100
|
+
{
|
|
101
|
+
intentType: 'enterCommandLineMode',
|
|
102
|
+
},
|
|
103
|
+
state,
|
|
104
|
+
),
|
|
105
|
+
).toEqual({
|
|
106
|
+
effectType: 'setInputState',
|
|
107
|
+
inputState: {
|
|
108
|
+
inputMode: 'command',
|
|
109
|
+
commandLine: ':',
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
it('updates the command line', () => {
|
|
114
|
+
expect(
|
|
115
|
+
intentToEffect(
|
|
116
|
+
{
|
|
117
|
+
intentType: 'setCommandLine',
|
|
118
|
+
commandLine: ':w',
|
|
119
|
+
},
|
|
120
|
+
state,
|
|
121
|
+
),
|
|
122
|
+
).toEqual({
|
|
123
|
+
effectType: 'setInputState',
|
|
124
|
+
inputState: {
|
|
125
|
+
inputMode: 'command',
|
|
126
|
+
commandLine: ':w',
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
it('exits command-line mode', () => {
|
|
131
|
+
expect(
|
|
132
|
+
intentToEffect(
|
|
133
|
+
{
|
|
134
|
+
intentType: 'exitCommandLineMode',
|
|
135
|
+
},
|
|
136
|
+
state,
|
|
137
|
+
),
|
|
138
|
+
).toEqual({
|
|
139
|
+
effectType: 'setInputState',
|
|
140
|
+
inputState: {
|
|
141
|
+
inputMode: 'normal',
|
|
142
|
+
normalBuffer: '',
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
it('returns to normal mode after executing a gibberish command line', () => {
|
|
147
|
+
expect(
|
|
148
|
+
intentToEffect(
|
|
149
|
+
{
|
|
150
|
+
intentType: 'executeCommandLine',
|
|
151
|
+
commandLine: ':sijbas',
|
|
152
|
+
},
|
|
153
|
+
state,
|
|
154
|
+
),
|
|
155
|
+
).toEqual({
|
|
156
|
+
effectType: 'setInputState',
|
|
157
|
+
inputState: {
|
|
158
|
+
inputMode: 'normal',
|
|
159
|
+
normalBuffer: '',
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
it('quits when the :q command is executed', () => {
|
|
164
|
+
expect(
|
|
165
|
+
intentToEffect(
|
|
166
|
+
{
|
|
167
|
+
intentType: 'executeCommandLine',
|
|
168
|
+
commandLine: ':q',
|
|
169
|
+
},
|
|
170
|
+
state,
|
|
171
|
+
),
|
|
172
|
+
).toEqual({
|
|
173
|
+
effectType: 'quit',
|
|
174
|
+
exitMessage: '',
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { UserInput } from '../domain/user-input.js';
|
|
2
|
+
import { InputState } from '../domain/input-state.js';
|
|
3
|
+
import { Intent } from '../domain/intent.js';
|
|
4
|
+
export declare function userInputToIntent(
|
|
5
|
+
userInput: UserInput,
|
|
6
|
+
inputState: InputState,
|
|
7
|
+
): Intent | undefined;
|
|
8
|
+
//# sourceMappingURL=user-input-to-intent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user-input-to-intent.d.ts","sourceRoot":"","sources":["../../src/application/user-input-to-intent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAG7C,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,SAAS,EACpB,UAAU,EAAE,UAAU,GACrB,MAAM,GAAG,SAAS,CAQpB"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// Derive the intent from the user input and the current input state.
|
|
2
|
+
export function userInputToIntent(userInput, inputState) {
|
|
3
|
+
switch (inputState.inputMode) {
|
|
4
|
+
case 'normal':
|
|
5
|
+
return normalUserInputToIntent(userInput, inputState.normalBuffer);
|
|
6
|
+
case 'command':
|
|
7
|
+
return commandUserInputToIntent(userInput, inputState.commandLine);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function normalUserInputToIntent(userInput, normalBuffer) {
|
|
11
|
+
if (userInput.userInputType === 'esc') {
|
|
12
|
+
return {
|
|
13
|
+
intentType: 'setNormalBuffer',
|
|
14
|
+
normalBuffer: '',
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
if (userInput.userInputType === 'character') {
|
|
18
|
+
return normalCharacterToIntent(userInput.string, normalBuffer);
|
|
19
|
+
}
|
|
20
|
+
switch (userInput.userInputType) {
|
|
21
|
+
case 'rightArrow':
|
|
22
|
+
return {
|
|
23
|
+
intentType: 'normalRight',
|
|
24
|
+
};
|
|
25
|
+
case 'leftArrow':
|
|
26
|
+
return {
|
|
27
|
+
intentType: 'normalLeft',
|
|
28
|
+
};
|
|
29
|
+
case 'downArrow':
|
|
30
|
+
return {
|
|
31
|
+
intentType: 'normalDown',
|
|
32
|
+
};
|
|
33
|
+
case 'upArrow':
|
|
34
|
+
return {
|
|
35
|
+
intentType: 'normalUp',
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function normalCharacterToIntent(character, normalBuffer) {
|
|
40
|
+
if (normalBuffer === '') {
|
|
41
|
+
switch (character) {
|
|
42
|
+
case 'l':
|
|
43
|
+
return {
|
|
44
|
+
intentType: 'normalRight',
|
|
45
|
+
};
|
|
46
|
+
case 'h':
|
|
47
|
+
return {
|
|
48
|
+
intentType: 'normalLeft',
|
|
49
|
+
};
|
|
50
|
+
case 'j':
|
|
51
|
+
return {
|
|
52
|
+
intentType: 'normalDown',
|
|
53
|
+
};
|
|
54
|
+
case 'k':
|
|
55
|
+
return {
|
|
56
|
+
intentType: 'normalUp',
|
|
57
|
+
};
|
|
58
|
+
case ':':
|
|
59
|
+
return {
|
|
60
|
+
intentType: 'enterCommandLineMode',
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
intentType: 'setNormalBuffer',
|
|
66
|
+
normalBuffer: normalBuffer + character,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function commandUserInputToIntent(userInput, commandLine) {
|
|
70
|
+
if (userInput.userInputType === 'esc') {
|
|
71
|
+
return {
|
|
72
|
+
intentType: 'exitCommandLineMode',
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
if (userInput.userInputType === 'enter') {
|
|
76
|
+
return {
|
|
77
|
+
intentType: 'executeCommandLine',
|
|
78
|
+
commandLine: commandLine,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
if (userInput.userInputType === 'backspace') {
|
|
82
|
+
if (commandLine.length < 2) {
|
|
83
|
+
return {
|
|
84
|
+
intentType: 'exitCommandLineMode',
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
intentType: 'setCommandLine',
|
|
89
|
+
commandLine: commandLine.slice(0, -1),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
if (userInput.userInputType === 'character') {
|
|
93
|
+
return {
|
|
94
|
+
intentType: 'setCommandLine',
|
|
95
|
+
commandLine: commandLine + userInput.string,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user-input-to-intent.test.d.ts","sourceRoot":"","sources":["../../src/application/user-input-to-intent.test.ts"],"names":[],"mappings":""}
|