reslop 0.1.4 → 0.1.5
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/CHANGELOG.md +10 -1
- package/README.md +21 -20
- package/lib/diff.js +71 -2
- package/lib/git.js +26 -0
- package/lib/keys.js +27 -6
- package/lib/render.js +145 -53
- package/lib/review.js +145 -3
- package/lib/select.js +7 -12
- package/lib/session.js +236 -22
- package/package.json +1 -1
package/lib/session.js
CHANGED
|
@@ -12,17 +12,16 @@ const { copyText } = require('./clipboard.js');
|
|
|
12
12
|
const { watchResize } = require('./sys.js');
|
|
13
13
|
const { fileEntries, itemPath } = require('./files.js');
|
|
14
14
|
const { Editor } = require('./editor.js');
|
|
15
|
-
const { refreshIndexPatches } = require('./diff.js');
|
|
15
|
+
const { refreshIndexPatches, blockAddText } = require('./diff.js');
|
|
16
16
|
|
|
17
17
|
const { renderFrame, presentRows, presentCursor } = render;
|
|
18
|
-
const { noteInnerWidth, todoInnerWidth } = render;
|
|
19
|
-
const { QUIT_FINISH, QUIT_CONTINUE } = render;
|
|
18
|
+
const { noteInnerWidth, todoInnerWidth, codeInnerWidth } = render;
|
|
20
19
|
const { actionFromKey, hitAction, decodeChunk } = keys;
|
|
21
|
-
const {
|
|
20
|
+
const { disabledActions } = keys;
|
|
22
21
|
const { cursorInWrap, wrapDoc, wrapMove } = wrap;
|
|
23
22
|
const { AUTOSAVE_MS, listReviewNames, loadTemplates } = review;
|
|
24
23
|
const { resolveReviewPath, loadReview, createStore } = review;
|
|
25
|
-
const { noteCounts, hasNotes, setFeedback, addTodo } = review;
|
|
24
|
+
const { noteCounts, hasNotes, setFeedback, setCode, addTodo } = review;
|
|
26
25
|
const { applyImportedNotes } = review;
|
|
27
26
|
const { setTodoText, removeTodo, flushReview, mergeTodos } = review;
|
|
28
27
|
const { feedbackKey, checkLabel, rankedTemplates } = review;
|
|
@@ -87,6 +86,13 @@ const itemFeedKey = (item) => {
|
|
|
87
86
|
return feedbackKey({ file, oldStart, newStart, blockId });
|
|
88
87
|
};
|
|
89
88
|
|
|
89
|
+
const canEditCode = (item) => {
|
|
90
|
+
if (!item || item.origin === 'todo') return false;
|
|
91
|
+
if (!item.hunk || !item.file) return false;
|
|
92
|
+
if (item.file.isBinary) return false;
|
|
93
|
+
return true;
|
|
94
|
+
};
|
|
95
|
+
|
|
90
96
|
const isAbortError = (error) => !!(error && error.code === 'ABORT');
|
|
91
97
|
|
|
92
98
|
const sameCursor = (a, b) => {
|
|
@@ -96,12 +102,26 @@ const sameCursor = (a, b) => {
|
|
|
96
102
|
};
|
|
97
103
|
|
|
98
104
|
const QUIT_CONFIRM = {
|
|
99
|
-
|
|
100
|
-
|
|
105
|
+
f: (session) => session.finishQuit('ready'),
|
|
106
|
+
c: (session) => session.finishQuit('editing'),
|
|
107
|
+
d: (session) => session.discardQuit(),
|
|
101
108
|
'ctrl-c': (session) => session.finishQuit('ready'),
|
|
102
109
|
escape: (session) => session.cancelQuit(),
|
|
103
110
|
};
|
|
104
111
|
|
|
112
|
+
const COMMIT_CONFIRM = {
|
|
113
|
+
c: (session) => session.startGitCommit('commit'),
|
|
114
|
+
a: (session) => session.startGitCommit('amend'),
|
|
115
|
+
f: (session) => session.startGitCommit('fixup'),
|
|
116
|
+
escape: (session) => session.cancelCommit(),
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const COMMIT_STATUS = {
|
|
120
|
+
commit: 'committed',
|
|
121
|
+
amend: 'amended',
|
|
122
|
+
fixup: 'fixup',
|
|
123
|
+
};
|
|
124
|
+
|
|
105
125
|
const COMPOSE_EDITS = ['backspace', 'delete', 'ctrl-z', 'ctrl-y'];
|
|
106
126
|
|
|
107
127
|
const COMPOSE_SPECIAL = {
|
|
@@ -117,7 +137,7 @@ const COMPOSE_SPECIAL = {
|
|
|
117
137
|
'ctrl-e': (session) => session.editor.end(),
|
|
118
138
|
'ctrl-z': (session) => session.editor.undoEdit(),
|
|
119
139
|
'ctrl-y': (session) => session.editor.redoEdit(),
|
|
120
|
-
tab: (session) => session.
|
|
140
|
+
tab: (session) => session.composeTab(),
|
|
121
141
|
};
|
|
122
142
|
|
|
123
143
|
const HANDLERS = {
|
|
@@ -130,6 +150,9 @@ const HANDLERS = {
|
|
|
130
150
|
files: (session) => session.onFiles(),
|
|
131
151
|
feedback: (session) => session.onFeedback(),
|
|
132
152
|
todo: (session) => session.onTodo(),
|
|
153
|
+
code: (session) => session.onCode(),
|
|
154
|
+
reload: (session) => session.onReload(),
|
|
155
|
+
commit: (session) => session.onCommit(),
|
|
133
156
|
open: (session) => session.onOpenFile(),
|
|
134
157
|
removeTodo: (session) => session.removeFocusedTodo(),
|
|
135
158
|
quit: (session) => session.onQuit(),
|
|
@@ -143,9 +166,12 @@ const HANDLERS = {
|
|
|
143
166
|
|
|
144
167
|
const KEY_MODE = {
|
|
145
168
|
confirmQuit: (session, key) => session.onConfirmQuit(key),
|
|
169
|
+
confirmCommit: (session, key) => session.onConfirmCommit(key),
|
|
146
170
|
compose: (session, key) => session.handleComposeKey(key),
|
|
147
171
|
};
|
|
148
172
|
|
|
173
|
+
const COMPOSE_LEAVE = ['next', 'prev', 'todo'];
|
|
174
|
+
|
|
149
175
|
const MOUSE_KIND = {
|
|
150
176
|
wheelUp: (session) => session.onScroll(-1),
|
|
151
177
|
wheelDown: (session) => session.onScroll(1),
|
|
@@ -200,6 +226,7 @@ class Session {
|
|
|
200
226
|
this.readFileSync = options.readFileSync ?? fs.readFileSync;
|
|
201
227
|
this.writeFileSync = options.writeFileSync ?? fs.writeFileSync;
|
|
202
228
|
this.mkdirSync = options.mkdirSync ?? fs.mkdirSync;
|
|
229
|
+
this.unlinkSync = options.unlinkSync ?? fs.unlinkSync;
|
|
203
230
|
this.now = options.now ?? systemNow;
|
|
204
231
|
this.forceNewReview = options.newReview === true;
|
|
205
232
|
this.readOnly = options.readOnly === true;
|
|
@@ -236,6 +263,7 @@ class Session {
|
|
|
236
263
|
this.mode = 'review';
|
|
237
264
|
this.editor = null;
|
|
238
265
|
this.composeKind = null;
|
|
266
|
+
this.commitKind = null;
|
|
239
267
|
this.composeTodoId = null;
|
|
240
268
|
this.composeBaseline = '';
|
|
241
269
|
this.todoFocus = 0;
|
|
@@ -530,6 +558,7 @@ class Session {
|
|
|
530
558
|
pr: 0,
|
|
531
559
|
todo: 0,
|
|
532
560
|
feedback: 0,
|
|
561
|
+
code: 0,
|
|
533
562
|
};
|
|
534
563
|
for (const item of this.items) {
|
|
535
564
|
if (!Object.hasOwn(counts, item.origin)) continue;
|
|
@@ -538,6 +567,7 @@ class Session {
|
|
|
538
567
|
const notes = noteCounts(this.notes);
|
|
539
568
|
counts.feedback = notes.feedback;
|
|
540
569
|
counts.todo = notes.todo;
|
|
570
|
+
counts.code = notes.code;
|
|
541
571
|
return counts;
|
|
542
572
|
}
|
|
543
573
|
|
|
@@ -569,6 +599,7 @@ class Session {
|
|
|
569
599
|
todos: this.todoTexts(),
|
|
570
600
|
todoFocus: this.clampedTodoFocus(),
|
|
571
601
|
todoEdit: this.todoEditView(),
|
|
602
|
+
codeOverlay: this.codeOverlayView(),
|
|
572
603
|
templates,
|
|
573
604
|
templateIndex: this.clampedTemplateIndex(templates),
|
|
574
605
|
};
|
|
@@ -601,18 +632,18 @@ class Session {
|
|
|
601
632
|
|
|
602
633
|
dispatch(action) {
|
|
603
634
|
if (this.mode === 'confirmQuit') return;
|
|
635
|
+
if (this.mode === 'confirmCommit') return;
|
|
604
636
|
if (this.mode === 'compose') {
|
|
605
|
-
if (action
|
|
606
|
-
return;
|
|
607
|
-
}
|
|
637
|
+
if (!COMPOSE_LEAVE.includes(action)) return;
|
|
608
638
|
this.commitCompose();
|
|
609
639
|
this.closeCompose();
|
|
610
640
|
}
|
|
611
641
|
if (this.pane === 'files') {
|
|
612
642
|
if (action === 'next') return void this.onFileMove(1);
|
|
613
643
|
if (action === 'prev') return void this.onFileMove(-1);
|
|
614
|
-
if (FILES_DISABLED.includes(action)) return;
|
|
615
644
|
}
|
|
645
|
+
const hidden = disabledActions(this.pane, this.current());
|
|
646
|
+
if (hidden.includes(action)) return;
|
|
616
647
|
const handler = HANDLERS[action];
|
|
617
648
|
if (!handler) return;
|
|
618
649
|
handler(this);
|
|
@@ -622,8 +653,7 @@ class Session {
|
|
|
622
653
|
return this.items[this.index] ?? null;
|
|
623
654
|
}
|
|
624
655
|
|
|
625
|
-
|
|
626
|
-
const here = this.index;
|
|
656
|
+
refreshFromRepo() {
|
|
627
657
|
this.loadPromise = null;
|
|
628
658
|
this.bumpLoad();
|
|
629
659
|
const options = this.loadOptions({
|
|
@@ -631,10 +661,6 @@ class Session {
|
|
|
631
661
|
});
|
|
632
662
|
const loaded = this.repo.load(this.cwd, this.paths, options);
|
|
633
663
|
this.applyLoaded(loaded);
|
|
634
|
-
this.index = here;
|
|
635
|
-
this.clampIndex();
|
|
636
|
-
this.syncReviewPath();
|
|
637
|
-
this.syncFileCursor();
|
|
638
664
|
this.scroll = 0;
|
|
639
665
|
this.clearSelection();
|
|
640
666
|
if (loaded.pending) {
|
|
@@ -645,6 +671,22 @@ class Session {
|
|
|
645
671
|
this.finishIfEmpty('reload');
|
|
646
672
|
}
|
|
647
673
|
|
|
674
|
+
reloadAfterChange() {
|
|
675
|
+
const here = this.index;
|
|
676
|
+
this.refreshFromRepo();
|
|
677
|
+
this.index = here;
|
|
678
|
+
this.clampIndex();
|
|
679
|
+
this.syncReviewPath();
|
|
680
|
+
this.syncFileCursor();
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
onReload() {
|
|
684
|
+
this.dismissed.clear();
|
|
685
|
+
this.status = '';
|
|
686
|
+
this.refreshFromRepo();
|
|
687
|
+
if (!this.done && !this.pendingExtras) this.status = 'reloaded';
|
|
688
|
+
}
|
|
689
|
+
|
|
648
690
|
clearSelection() {
|
|
649
691
|
this.selection = null;
|
|
650
692
|
this.mouseAnchor = null;
|
|
@@ -795,7 +837,7 @@ class Session {
|
|
|
795
837
|
let ok = false;
|
|
796
838
|
try {
|
|
797
839
|
this.repo.revertFile(this.top, rel, items);
|
|
798
|
-
this.status = '
|
|
840
|
+
this.status = 'dropped';
|
|
799
841
|
ok = true;
|
|
800
842
|
} catch (error) {
|
|
801
843
|
this.status = error.message;
|
|
@@ -849,7 +891,7 @@ class Session {
|
|
|
849
891
|
if (!this.guardWritable(item)) return;
|
|
850
892
|
this.applyGit(
|
|
851
893
|
item,
|
|
852
|
-
'
|
|
894
|
+
'dropped',
|
|
853
895
|
(top, current) => this.repo.revert(top, current),
|
|
854
896
|
() => {
|
|
855
897
|
if (needsReload(item)) this.dismissed.add(itemKey(item));
|
|
@@ -911,6 +953,23 @@ class Session {
|
|
|
911
953
|
this.exitCode = 0;
|
|
912
954
|
}
|
|
913
955
|
|
|
956
|
+
removeReviewFile() {
|
|
957
|
+
const file = this.notes && this.notes.reviewPath;
|
|
958
|
+
if (!file) return;
|
|
959
|
+
try {
|
|
960
|
+
this.unlinkSync(file);
|
|
961
|
+
} catch {
|
|
962
|
+
// ignore missing review file
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
discardQuit() {
|
|
967
|
+
if (this.notes) this.notes.dirty = false;
|
|
968
|
+
if (!this.didResumeReview) this.removeReviewFile();
|
|
969
|
+
this.done = true;
|
|
970
|
+
this.exitCode = 0;
|
|
971
|
+
}
|
|
972
|
+
|
|
914
973
|
cancelQuit() {
|
|
915
974
|
this.mode = 'review';
|
|
916
975
|
this.status = '';
|
|
@@ -922,6 +981,69 @@ class Session {
|
|
|
922
981
|
if (handler) handler(this);
|
|
923
982
|
}
|
|
924
983
|
|
|
984
|
+
canCommit() {
|
|
985
|
+
if (this.readOnly || this.rev || this.change) {
|
|
986
|
+
this.status = 'read only';
|
|
987
|
+
return false;
|
|
988
|
+
}
|
|
989
|
+
for (const item of this.items) {
|
|
990
|
+
if (isReadOnlyOrigin(item.origin)) {
|
|
991
|
+
this.status = 'read only';
|
|
992
|
+
return false;
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
return true;
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
onCommit() {
|
|
999
|
+
if (!this.canCommit()) return;
|
|
1000
|
+
this.mode = 'confirmCommit';
|
|
1001
|
+
this.status = '';
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
cancelCommit() {
|
|
1005
|
+
this.mode = 'review';
|
|
1006
|
+
this.commitKind = null;
|
|
1007
|
+
this.status = '';
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
startGitCommit(kind) {
|
|
1011
|
+
this.commitKind = kind;
|
|
1012
|
+
let text = '';
|
|
1013
|
+
if (kind === 'fixup') text = 'HEAD';
|
|
1014
|
+
if (kind === 'amend' && this.repo.lastMessage) {
|
|
1015
|
+
text = this.repo.lastMessage(this.top) ?? '';
|
|
1016
|
+
}
|
|
1017
|
+
this.openCompose('commit', text);
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
onConfirmCommit(key) {
|
|
1021
|
+
const commitKey = key.length === 1 ? key.toLowerCase() : key;
|
|
1022
|
+
const handler = COMMIT_CONFIRM[commitKey];
|
|
1023
|
+
if (handler) handler(this);
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
finishGitCommit() {
|
|
1027
|
+
const kind = this.commitKind;
|
|
1028
|
+
const message = this.editor ? this.editor.text : '';
|
|
1029
|
+
if (kind !== 'fixup' && !message.trim()) {
|
|
1030
|
+
this.status = 'empty commit message';
|
|
1031
|
+
return;
|
|
1032
|
+
}
|
|
1033
|
+
try {
|
|
1034
|
+
this.repo.commit(this.top, kind, message);
|
|
1035
|
+
} catch (error) {
|
|
1036
|
+
this.status = error.message;
|
|
1037
|
+
return;
|
|
1038
|
+
}
|
|
1039
|
+
this.closeCompose();
|
|
1040
|
+
this.dismissed.clear();
|
|
1041
|
+
this.refreshFromRepo();
|
|
1042
|
+
if (!this.done && !this.pendingExtras) {
|
|
1043
|
+
this.status = COMMIT_STATUS[kind] ?? 'committed';
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
|
|
925
1047
|
onFeedback() {
|
|
926
1048
|
if (this.pane === 'files') {
|
|
927
1049
|
this.status = 'not a diff block';
|
|
@@ -952,6 +1074,22 @@ class Session {
|
|
|
952
1074
|
this.createTodo(file);
|
|
953
1075
|
}
|
|
954
1076
|
|
|
1077
|
+
onCode() {
|
|
1078
|
+
if (this.pane === 'files') {
|
|
1079
|
+
this.status = 'not a diff block';
|
|
1080
|
+
return;
|
|
1081
|
+
}
|
|
1082
|
+
const item = this.current();
|
|
1083
|
+
if (!canEditCode(item)) {
|
|
1084
|
+
this.status = 'not a diff block';
|
|
1085
|
+
return;
|
|
1086
|
+
}
|
|
1087
|
+
const prev = this.notes.code.get(itemFeedKey(item));
|
|
1088
|
+
const original = blockAddText(item.hunk, item.blockId);
|
|
1089
|
+
const text = prev ? prev.text : original;
|
|
1090
|
+
this.openCompose('code', text);
|
|
1091
|
+
}
|
|
1092
|
+
|
|
955
1093
|
todoPageIndex(file) {
|
|
956
1094
|
return this.items.findIndex(
|
|
957
1095
|
(item) => item.origin === 'todo' && itemPath(item) === file,
|
|
@@ -1084,6 +1222,29 @@ class Session {
|
|
|
1084
1222
|
return;
|
|
1085
1223
|
}
|
|
1086
1224
|
if (this.composeKind === 'todo') this.commitTodo(text);
|
|
1225
|
+
if (this.composeKind === 'code') this.commitCode(text);
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
commitCode(text) {
|
|
1229
|
+
const item = this.current();
|
|
1230
|
+
if (!canEditCode(item)) return;
|
|
1231
|
+
const original = blockAddText(item.hunk, item.blockId);
|
|
1232
|
+
const key = itemFeedKey(item);
|
|
1233
|
+
const hunk = item.hunk;
|
|
1234
|
+
const note = {
|
|
1235
|
+
file: itemPath(item),
|
|
1236
|
+
oldStart: hunk.oldStart ?? 0,
|
|
1237
|
+
newStart: hunk.newStart ?? 0,
|
|
1238
|
+
blockId: item.blockId ?? 0,
|
|
1239
|
+
origin: item.origin,
|
|
1240
|
+
header: hunk.header ?? '',
|
|
1241
|
+
text,
|
|
1242
|
+
};
|
|
1243
|
+
if (text === original) {
|
|
1244
|
+
setCode(this.notes, key, { ...note, clear: true });
|
|
1245
|
+
return;
|
|
1246
|
+
}
|
|
1247
|
+
setCode(this.notes, key, note);
|
|
1087
1248
|
}
|
|
1088
1249
|
|
|
1089
1250
|
commitTodo(text) {
|
|
@@ -1114,6 +1275,7 @@ class Session {
|
|
|
1114
1275
|
this.mode = 'review';
|
|
1115
1276
|
this.editor = null;
|
|
1116
1277
|
this.composeKind = null;
|
|
1278
|
+
this.commitKind = null;
|
|
1117
1279
|
this.composeTodoId = null;
|
|
1118
1280
|
this.composeBaseline = '';
|
|
1119
1281
|
this.templateIndex = -1;
|
|
@@ -1174,7 +1336,9 @@ class Session {
|
|
|
1174
1336
|
|
|
1175
1337
|
composeView() {
|
|
1176
1338
|
if (this.mode !== 'compose' || !this.editor) return null;
|
|
1177
|
-
if (this.composeKind !== 'feedback')
|
|
1339
|
+
if (this.composeKind !== 'feedback' && this.composeKind !== 'commit') {
|
|
1340
|
+
return null;
|
|
1341
|
+
}
|
|
1178
1342
|
const kind = this.composeKind;
|
|
1179
1343
|
const text = this.editor.text;
|
|
1180
1344
|
const cursor = this.editor.cursor;
|
|
@@ -1187,6 +1351,34 @@ class Session {
|
|
|
1187
1351
|
return { cursor: this.editor.cursor };
|
|
1188
1352
|
}
|
|
1189
1353
|
|
|
1354
|
+
liveCodeText() {
|
|
1355
|
+
const item = this.current();
|
|
1356
|
+
if (!canEditCode(item)) return null;
|
|
1357
|
+
if (this.mode === 'compose' && this.composeKind === 'code' && this.editor) {
|
|
1358
|
+
return this.editor.text;
|
|
1359
|
+
}
|
|
1360
|
+
if (!this.notes) return null;
|
|
1361
|
+
const note = this.notes.code.get(itemFeedKey(item));
|
|
1362
|
+
if (!note) return null;
|
|
1363
|
+
return note.text;
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
codeOverlayView() {
|
|
1367
|
+
const text = this.liveCodeText();
|
|
1368
|
+
if (text === null) return null;
|
|
1369
|
+
const editing = this.mode === 'compose' && this.composeKind === 'code';
|
|
1370
|
+
const cursor = editing && this.editor ? this.editor.cursor : null;
|
|
1371
|
+
return { text, keepEmpty: editing, cursor };
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
composeTab() {
|
|
1375
|
+
if (this.composeKind === 'code') {
|
|
1376
|
+
this.editor.insert('\t');
|
|
1377
|
+
return;
|
|
1378
|
+
}
|
|
1379
|
+
this.applyTemplate();
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1190
1382
|
fileTodos(rel) {
|
|
1191
1383
|
if (!this.notes || !rel) return [];
|
|
1192
1384
|
const todos = [];
|
|
@@ -1268,6 +1460,10 @@ class Session {
|
|
|
1268
1460
|
}
|
|
1269
1461
|
|
|
1270
1462
|
saveCompose() {
|
|
1463
|
+
if (this.composeKind === 'commit') {
|
|
1464
|
+
this.finishGitCommit();
|
|
1465
|
+
return;
|
|
1466
|
+
}
|
|
1271
1467
|
this.commitCompose();
|
|
1272
1468
|
if (this.composeKind === 'feedback') {
|
|
1273
1469
|
const next = this.editor ? this.editor.text : '';
|
|
@@ -1280,7 +1476,10 @@ class Session {
|
|
|
1280
1476
|
|
|
1281
1477
|
autosave() {
|
|
1282
1478
|
const text = this.editor ? this.editor.text : '';
|
|
1283
|
-
|
|
1479
|
+
const editingCode = this.mode === 'compose' && this.composeKind === 'code';
|
|
1480
|
+
if (this.mode === 'compose' && (editingCode || text.trim())) {
|
|
1481
|
+
this.commitCompose();
|
|
1482
|
+
}
|
|
1284
1483
|
if (this.notes && this.notes.dirty) this.flushReview();
|
|
1285
1484
|
}
|
|
1286
1485
|
|
|
@@ -1306,6 +1505,11 @@ class Session {
|
|
|
1306
1505
|
this.moveTodoLine(delta, todoInnerWidth(size.width));
|
|
1307
1506
|
return;
|
|
1308
1507
|
}
|
|
1508
|
+
if (this.composeKind === 'code') {
|
|
1509
|
+
const inner = codeInnerWidth(size.width, this.layout);
|
|
1510
|
+
this.editor.moveLine(delta, inner);
|
|
1511
|
+
return;
|
|
1512
|
+
}
|
|
1309
1513
|
const width = noteInnerWidth(size.width);
|
|
1310
1514
|
const shown = this.shownTemplates();
|
|
1311
1515
|
if (shown.length && this.composeKind === 'feedback') {
|
|
@@ -1355,10 +1559,20 @@ class Session {
|
|
|
1355
1559
|
this.selectTemplate(this.templateIndex);
|
|
1356
1560
|
return;
|
|
1357
1561
|
}
|
|
1562
|
+
if (this.composeKind === 'code') {
|
|
1563
|
+
this.editor.insert('\n');
|
|
1564
|
+
this.resetBlink();
|
|
1565
|
+
return;
|
|
1566
|
+
}
|
|
1358
1567
|
this.saveCompose();
|
|
1359
1568
|
return;
|
|
1360
1569
|
}
|
|
1361
1570
|
if (key === 'escape' || key === 'ctrl-s') {
|
|
1571
|
+
if (this.composeKind === 'commit' && key === 'escape') {
|
|
1572
|
+
this.closeCompose();
|
|
1573
|
+
this.status = '';
|
|
1574
|
+
return;
|
|
1575
|
+
}
|
|
1362
1576
|
this.saveCompose();
|
|
1363
1577
|
return;
|
|
1364
1578
|
}
|