From 1de72b2700c1d11abe1ebe59f5885b11d68a9a65 Mon Sep 17 00:00:00 2001 From: Patrik Zander Date: Fri, 2 Aug 2024 23:25:52 +0200 Subject: [PATCH 01/14] Wip add monaco to code hints (todo size) --- .../shared/exercise-hint-shared.module.ts | 3 +- .../shared/solution-entry.component.html | 12 ++---- .../shared/solution-entry.component.ts | 37 +++++-------------- .../monaco-editor/monaco-editor.component.ts | 10 +++++ 4 files changed, 25 insertions(+), 37 deletions(-) diff --git a/src/main/webapp/app/exercises/shared/exercise-hint/shared/exercise-hint-shared.module.ts b/src/main/webapp/app/exercises/shared/exercise-hint/shared/exercise-hint-shared.module.ts index cc3675a9cbb4..e6f4e965ea3e 100644 --- a/src/main/webapp/app/exercises/shared/exercise-hint/shared/exercise-hint-shared.module.ts +++ b/src/main/webapp/app/exercises/shared/exercise-hint/shared/exercise-hint-shared.module.ts @@ -5,9 +5,10 @@ import { SolutionEntryComponent } from 'app/exercises/shared/exercise-hint/share import { AceEditorModule } from 'app/shared/markdown-editor/ace-editor/ace-editor.module'; import { CodeHintContainerComponent } from 'app/exercises/shared/exercise-hint/shared/code-hint-container.component'; import { ArtemisMarkdownModule } from 'app/shared/markdown.module'; +import { MonacoEditorModule } from 'app/shared/monaco-editor/monaco-editor.module'; @NgModule({ - imports: [ArtemisSharedModule, AceEditorModule, ArtemisMarkdownModule], + imports: [ArtemisSharedModule, AceEditorModule, ArtemisMarkdownModule, MonacoEditorModule], declarations: [SolutionEntryComponent, CodeHintContainerComponent, CastToCodeHintPipe], exports: [SolutionEntryComponent, CodeHintContainerComponent, CastToCodeHintPipe], }) diff --git a/src/main/webapp/app/exercises/shared/exercise-hint/shared/solution-entry.component.html b/src/main/webapp/app/exercises/shared/exercise-hint/shared/solution-entry.component.html index 6de26e13cf0e..e34783e0fc15 100644 --- a/src/main/webapp/app/exercises/shared/exercise-hint/shared/solution-entry.component.html +++ b/src/main/webapp/app/exercises/shared/exercise-hint/shared/solution-entry.component.html @@ -1,12 +1,6 @@
{{ solutionEntry.filePath }}
- +
+ +
diff --git a/src/main/webapp/app/exercises/shared/exercise-hint/shared/solution-entry.component.ts b/src/main/webapp/app/exercises/shared/exercise-hint/shared/solution-entry.component.ts index 5107f4ba59d1..05fb0109c006 100644 --- a/src/main/webapp/app/exercises/shared/exercise-hint/shared/solution-entry.component.ts +++ b/src/main/webapp/app/exercises/shared/exercise-hint/shared/solution-entry.component.ts @@ -1,9 +1,8 @@ import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; - -import { AceEditorComponent } from 'app/shared/markdown-editor/ace-editor/ace-editor.component'; import { faTimes } from '@fortawesome/free-solid-svg-icons'; import { ProgrammingExerciseSolutionEntry } from 'app/entities/hestia/programming-exercise-solution-entry.model'; +import { MonacoEditorComponent } from 'app/shared/monaco-editor/monaco-editor.component'; @Component({ selector: 'jhi-solution-entry', @@ -11,7 +10,7 @@ import { ProgrammingExerciseSolutionEntry } from 'app/entities/hestia/programmin }) export class SolutionEntryComponent implements OnInit { @ViewChild('editor', { static: true }) - editor: AceEditorComponent; + editor: MonacoEditorComponent; @Input() solutionEntry: ProgrammingExerciseSolutionEntry; @@ -21,7 +20,9 @@ export class SolutionEntryComponent implements OnInit { @Output() onRemoveEntry: EventEmitter = new EventEmitter(); - faTimes = faTimes; + editorHeight = 20; + + protected readonly faTimes = faTimes; constructor(protected route: ActivatedRoute) {} @@ -29,32 +30,14 @@ export class SolutionEntryComponent implements OnInit { this.setupEditor(); } - emitRemovalEvent() { - this.onRemoveEntry.emit(); - } - - onEditorContentChange(value: any) { + onEditorContentChange(value: string) { this.solutionEntry.code = value; } private setupEditor() { - const line = this.solutionEntry.line; - - this.editor.getEditor().setOptions({ - animatedScroll: true, - maxLines: Infinity, - showPrintMargin: false, - }); - // Ensure that the line counter is according to the solution entry - this.editor.getEditor().session.gutterRenderer = { - getWidth(session: any, lastLineNumber: number, config: any) { - return this.getText(session, lastLineNumber).toString().length * config.characterWidth; - }, - getText(session: any, row: number): string | number { - return !line ? '' : row + line; - }, - }; - this.editor.getEditor().getSession().setValue(this.solutionEntry.code); - this.editor.getEditor().resize(); + const startLine = this.solutionEntry.line ?? 1; + this.editor.setStartLineNumber(startLine); + this.editor.setText(this.solutionEntry.code ?? ''); + this.editor.layout(); } } diff --git a/src/main/webapp/app/shared/monaco-editor/monaco-editor.component.ts b/src/main/webapp/app/shared/monaco-editor/monaco-editor.component.ts index b7f65e96c0dc..250543ac706f 100644 --- a/src/main/webapp/app/shared/monaco-editor/monaco-editor.component.ts +++ b/src/main/webapp/app/shared/monaco-editor/monaco-editor.component.ts @@ -364,4 +364,14 @@ export class MonacoEditorComponent implements OnInit, OnDestroy { wordWrap: value ? 'on' : 'off', }); } + + /** + * Sets the line number from which the editor should start counting. + * @param startLineNumber The line number to start counting from (>= 1). + */ + setStartLineNumber(startLineNumber: number): void { + this._editor.updateOptions({ + lineNumbers: (number) => `${startLineNumber + number - 1}`, + }); + } } From 5e61f221469d7b8b133902bc89f08f45bcb15baf Mon Sep 17 00:00:00 2001 From: Patrik Zander Date: Fri, 2 Aug 2024 23:44:14 +0200 Subject: [PATCH 02/14] Remove unused route --- .../shared/exercise-hint/shared/solution-entry.component.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/webapp/app/exercises/shared/exercise-hint/shared/solution-entry.component.ts b/src/main/webapp/app/exercises/shared/exercise-hint/shared/solution-entry.component.ts index 05fb0109c006..8611ab5bccef 100644 --- a/src/main/webapp/app/exercises/shared/exercise-hint/shared/solution-entry.component.ts +++ b/src/main/webapp/app/exercises/shared/exercise-hint/shared/solution-entry.component.ts @@ -1,5 +1,4 @@ import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; import { faTimes } from '@fortawesome/free-solid-svg-icons'; import { ProgrammingExerciseSolutionEntry } from 'app/entities/hestia/programming-exercise-solution-entry.model'; import { MonacoEditorComponent } from 'app/shared/monaco-editor/monaco-editor.component'; @@ -24,7 +23,7 @@ export class SolutionEntryComponent implements OnInit { protected readonly faTimes = faTimes; - constructor(protected route: ActivatedRoute) {} + constructor() {} ngOnInit() { this.setupEditor(); From 8f4b3cce550823d6c367f25da4a12526f94381b7 Mon Sep 17 00:00:00 2001 From: Patrik Zander Date: Fri, 2 Aug 2024 23:46:47 +0200 Subject: [PATCH 03/14] Add content height listener --- .../monaco-editor/monaco-editor.component.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/main/webapp/app/shared/monaco-editor/monaco-editor.component.ts b/src/main/webapp/app/shared/monaco-editor/monaco-editor.component.ts index 250543ac706f..c3fc3f60d887 100644 --- a/src/main/webapp/app/shared/monaco-editor/monaco-editor.component.ts +++ b/src/main/webapp/app/shared/monaco-editor/monaco-editor.component.ts @@ -96,6 +96,11 @@ export class MonacoEditorComponent implements OnInit, OnDestroy { @Output() textChanged = new EventEmitter(); + @Output() + contentHeightChanged = new EventEmitter(); + + private contentHeightListener?: monaco.IDisposable; + private textChangedListener?: monaco.IDisposable; private textChangedEmitTimeout?: NodeJS.Timeout; ngOnInit(): void { @@ -104,10 +109,16 @@ export class MonacoEditorComponent implements OnInit, OnDestroy { }); resizeObserver.observe(this.monacoEditorContainerElement); - this._editor.onDidChangeModelContent(() => { + this.textChangedListener = this._editor.onDidChangeModelContent(() => { this.emitTextChangeEvent(); }, this); + this.contentHeightListener = this._editor.onDidContentSizeChange((event) => { + if (event.contentHeightChanged) { + this.contentHeightChanged.emit(event.contentHeight + this._editor.getOption(monaco.editor.EditorOption.lineHeight)); + } + }); + this.themeSubscription = this.themeService.getCurrentThemeObservable().subscribe((theme) => this.changeTheme(theme)); } @@ -115,6 +126,8 @@ export class MonacoEditorComponent implements OnInit, OnDestroy { this.reset(); this._editor.dispose(); this.themeSubscription?.unsubscribe(); + this.textChangedListener?.dispose(); + this.contentHeightListener?.dispose(); } private emitTextChangeEvent() { From 6ff34603b8fdba9b678a34c2f9b56d633399576e Mon Sep 17 00:00:00 2001 From: Patrik Zander Date: Sat, 3 Aug 2024 00:21:28 +0200 Subject: [PATCH 04/14] Adjust styling of code hint modals --- ...anual-solution-entry-creation-modal.component.html | 4 ++-- .../solution-entry-details-modal.component.html | 4 ++-- .../shared/solution-entry.component.html | 11 +++++++++-- .../exercise-hint/shared/solution-entry.component.ts | 10 ++++++++-- .../shared/monaco-editor/monaco-editor.component.ts | 4 ++++ 5 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/main/webapp/app/exercises/programming/hestia/generation-overview/manual-solution-entry-creation-modal/manual-solution-entry-creation-modal.component.html b/src/main/webapp/app/exercises/programming/hestia/generation-overview/manual-solution-entry-creation-modal/manual-solution-entry-creation-modal.component.html index 8d981203bf68..9e3549414d51 100644 --- a/src/main/webapp/app/exercises/programming/hestia/generation-overview/manual-solution-entry-creation-modal/manual-solution-entry-creation-modal.component.html +++ b/src/main/webapp/app/exercises/programming/hestia/generation-overview/manual-solution-entry-creation-modal/manual-solution-entry-creation-modal.component.html @@ -27,8 +27,8 @@