Skip to content

Commit 286ac9b

Browse files
committed
Updates to console repl live input to handle multi-line history entries properly
1 parent ac323bc commit 286ac9b

File tree

1 file changed

+50
-32
lines changed

1 file changed

+50
-32
lines changed

src/vs/workbench/contrib/positronConsole/browser/components/consoleReplLiveInput.tsx

+50-32
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { KeyCode } from 'vs/base/common/keyCodes';
1111
import { generateUuid } from 'vs/base/common/uuid';
1212
import { DisposableStore } from 'vs/base/common/lifecycle';
1313
import { HistoryNavigator2 } from 'vs/base/common/history';
14+
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
1415
import { useStateRef } from 'vs/base/browser/ui/react/useStateRef';
1516
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
1617
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
@@ -26,7 +27,6 @@ import { IInputHistoryEntry } from 'vs/workbench/contrib/executionHistory/common
2627
import { SelectionClipboardContributionID } from 'vs/workbench/contrib/codeEditor/browser/selectionClipboard';
2728
import { usePositronConsoleContext } from 'vs/workbench/contrib/positronConsole/browser/positronConsoleContext';
2829
import { RuntimeCodeFragmentStatus } from 'vs/workbench/services/languageRuntime/common/languageRuntimeService';
29-
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
3030

3131
// ConsoleReplLiveInputProps interface.
3232
export interface ConsoleReplLiveInputProps {
@@ -51,6 +51,26 @@ export const ConsoleReplLiveInput = forwardRef<HTMLDivElement, ConsoleReplLiveIn
5151
const [, setCurrentCodeFragment, refCurrentCodeFragment] = useStateRef<string | undefined>(undefined);
5252
const [, setCodeEditorWidth, refCodeEditorWidth] = useStateRef(props.width);
5353

54+
/**
55+
* Updates the code editor widget position to such that the cursor
56+
* appers on the last line and the last column.
57+
*/
58+
const updateCodeEditorWidgetPositionToEnd = () => {
59+
// Get the model. If it isn't null (which it won't be), set the code editor widget
60+
// position.
61+
const textModel = refCodeEditorWidget.current.getModel();
62+
if (textModel) {
63+
const lineNumber = textModel.getLineCount();
64+
refCodeEditorWidget.current.setPosition({
65+
lineNumber,
66+
column: textModel.getLineContent(lineNumber).length + 1
67+
});
68+
69+
// Ensure that the code editor widget is scrolled into view.
70+
refContainer.current?.scrollIntoView({ behavior: 'auto' });
71+
}
72+
};
73+
5474
// Memoize the key down event handler.
5575
const keyDownHandler = useCallback(async (e: IKeyboardEvent) => {
5676
if (e.keyCode === KeyCode.UpArrow) {
@@ -65,8 +85,8 @@ export const ConsoleReplLiveInput = forwardRef<HTMLDivElement, ConsoleReplLiveIn
6585
// Get the current history entry, set it as the value of the code editor widget, and move to the previous entry.
6686
const inputHistoryEntry = refHistoryNavigator.current.current();
6787
refCodeEditorWidget.current.setValue(inputHistoryEntry.input);
68-
refCodeEditorWidget.current.setPosition({ lineNumber: 1, column: inputHistoryEntry.input.length + 1 });
6988
refHistoryNavigator.current.previous();
89+
updateCodeEditorWidgetPositionToEnd();
7090
}
7191

7292
// Eat the event.
@@ -79,15 +99,17 @@ export const ConsoleReplLiveInput = forwardRef<HTMLDivElement, ConsoleReplLiveIn
7999
if (refHistoryNavigator.current.isAtEnd()) {
80100
if (refCurrentCodeFragment.current !== undefined) {
81101
refCodeEditorWidget.current.setValue(refCurrentCodeFragment.current);
82-
refCodeEditorWidget.current.setPosition({ lineNumber: 1, column: refCurrentCodeFragment.current.length + 1 });
102+
//refCodeEditorWidget.current.setPosition({ lineNumber: 1, column: refCurrentCodeFragment.current.length + 1 });
83103
setCurrentCodeFragment(undefined);
84104
}
85105
} else {
86106
// Move to the next history entry and set it as the value of the code editor widget.
87107
const inputHistoryEntry = refHistoryNavigator.current.next();
88108
refCodeEditorWidget.current.setValue(inputHistoryEntry.input);
89-
refCodeEditorWidget.current.setPosition({ lineNumber: 1, column: inputHistoryEntry.input.length + 1 });
109+
// refCodeEditorWidget.current.setPosition({ lineNumber: 1, column: inputHistoryEntry.input.length + 1 });
90110
}
111+
112+
updateCodeEditorWidgetPositionToEnd();
91113
}
92114

93115
// Eat the event.
@@ -133,13 +155,8 @@ export const ConsoleReplLiveInput = forwardRef<HTMLDivElement, ConsoleReplLiveIn
133155

134156
// If we're supposed to execute the code fragment, do it.
135157
if (executeCode) {
136-
// // Execute the code.
137-
// const id = `fragment-${generateUuid()}`;
138-
// props.positronConsoleInstance.runtime.execute(
139-
// codeFragment,
140-
// id,
141-
// RuntimeCodeExecutionMode.Interactive,
142-
// RuntimeErrorBehavior.Continue);
158+
// Execute the code fragment.
159+
props.executeCode(codeFragment);
143160

144161
// If the code fragment contains more than whitespace characters, add it to the history navigator.
145162
if (codeFragment.trim().length) {
@@ -157,11 +174,13 @@ export const ConsoleReplLiveInput = forwardRef<HTMLDivElement, ConsoleReplLiveIn
157174
}
158175
}
159176

160-
props.executeCode(codeFragment);
161-
162177
// Reset the model for the next input.
163178
refCodeEditorWidget.current.setValue('');
164179
}
180+
181+
// Eat the event.
182+
e.preventDefault();
183+
e.stopPropagation();
165184
}
166185
}, []);
167186

@@ -180,6 +199,24 @@ export const ConsoleReplLiveInput = forwardRef<HTMLDivElement, ConsoleReplLiveIn
180199
setHistoryNavigator(new HistoryNavigator2<IInputHistoryEntry>(inputHistoryEntries.slice(-1000), 1000)); // TODO@softwarenerd - get 1000 from settings.
181200
}
182201

202+
// Create the resource URI.
203+
const uri = URI.from({
204+
scheme: Schemas.inMemory,
205+
path: `/repl-${props.positronConsoleInstance.runtime.metadata.languageId}-${generateUuid()}`
206+
});
207+
208+
// Create language selection.
209+
const languageSelection = positronConsoleContext.languageService.createById(props.positronConsoleInstance.runtime.metadata.languageId);
210+
211+
// Create text model; this is the backing store for the Monaco editor that receives
212+
// the user's input.
213+
const textModel = positronConsoleContext.modelService.createModel(
214+
'', // initial value
215+
languageSelection, // language selection
216+
uri, // resource URI
217+
false // this widget is not simple
218+
);
219+
183220
// Create the code editor widget.
184221
const codeEditorWidget = positronConsoleContext.instantiationService.createInstance(
185222
CodeEditorWidget,
@@ -205,25 +242,6 @@ export const ConsoleReplLiveInput = forwardRef<HTMLDivElement, ConsoleReplLiveIn
205242
disposableStore.add(codeEditorWidget);
206243
setCodeEditorWidget(codeEditorWidget);
207244

208-
// Create the resource URI.
209-
const uri = URI.from({
210-
scheme: Schemas.inMemory,
211-
path: `/repl-${props.positronConsoleInstance.runtime.metadata.languageId}-${generateUuid()}`
212-
});
213-
214-
// Create language selection.
215-
// const languageId = positronConsoleContext.languageService.getLanguageIdByLanguageName(props.positronConsoleInstance.runtime.metadata.language);
216-
const languageSelection = positronConsoleContext.languageService.createById(props.positronConsoleInstance.runtime.metadata.languageId);
217-
218-
// Create text model; this is the backing store for the Monaco editor that receives
219-
// the user's input.
220-
const textModel = positronConsoleContext.modelService.createModel(
221-
'', // initial value
222-
languageSelection, // language selection
223-
uri, // resource URI
224-
false // this widget is not simple
225-
);
226-
227245
// Attach the text model.
228246
codeEditorWidget.setModel(textModel);
229247

0 commit comments

Comments
 (0)