rfellows commented on code in PR #10144:
URL: https://github.com/apache/nifi/pull/10144#discussion_r2245275739


##########
nifi-frontend/src/main/frontend/apps/nifi/src/app/ui/common/property-table/editors/nf-editor/nf-editor.component.ts:
##########
@@ -88,40 +129,126 @@ export class NfEditor implements OnDestroy {
     @Output() exit: EventEmitter<void> = new EventEmitter<void>();
 
     itemSet = false;
-    getParametersSet = false;
-
+    parameterConfigSet = false;
+    nfLanguageDefinition: NfLanguageDefinition | null = null;
     nfEditorForm: FormGroup;
     showSensitiveHelperText = false;
     supportsEl = false;
     supportsParameters = false;
     blank = false;
 
-    mode!: string;
     parameters: Parameter[] | null = null;
-
-    editor!: Editor;
+    private _codemirrorConfig: CodeMirrorConfig = {
+        plugins: [],
+        focusOnInit: true
+    };
+
+    // Styling configuration
+    editorStyling = {
+        width: '100%',
+        height: '108px'
+    };
+
+    // Language configuration
+    languageConfig = {
+        language: this.nifiLanguagePackage.getLanguageId(),
+        languages: [] as LanguageDescription[]
+    };
+
+    // Dynamic config getter that includes disabled state
+    get codemirrorConfig(): CodeMirrorConfig {
+        return {
+            ...this._codemirrorConfig,
+            disabled: this.readonly || this.blank,
+            readOnly: this.readonly || this.blank
+        };
+    }
 
     constructor(
         private formBuilder: FormBuilder,
         private viewContainerRef: ViewContainerRef,
-        private renderer: Renderer2,
-        private nfel: NfEl,
-        private nfpr: NfPr
+        private nifiLanguagePackage: CodemirrorNifiLanguagePackage
     ) {
         this.nfEditorForm = this.formBuilder.group({
             value: new FormControl(''),
             setEmptyString: new FormControl(false)
         });
     }
 
-    codeMirrorLoaded(codeEditor: any): void {
-        this.editor = codeEditor.codeMirror;
+    initializeCodeMirror(): void {
+        if (this.itemSet && this.parameterConfigSet) {
+            const setup: Extension[] = [
+                lineNumbers(),
+                history(),
+                indentUnit.of('    '),
+                parameterHighlightPlugin,
+                elFunctionHighlightPlugin,
+                EditorView.lineWrapping,
+                rectangularSelection(),
+                crosshairCursor(),
+                EditorState.allowMultipleSelections.of(true),
+                indentOnInput(),
+                highlightSpecialChars(),
+                syntaxHighlighting(highlightStyle),
+                syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
+                bracketMatching(),
+                closeBrackets(),
+                highlightActiveLine(),
+                highlightSelectionMatches(),
+                [highlightActiveLineGutter(), Prec.highest(lineNumbers())],
+                autocompletion(),
+                EditorView.contentAttributes.of({ 'aria-label': 'Code Editor' 
}),
+                keymap.of([
+                    { key: 'Mod-Enter', run: () => true }, // ignore Mod-Enter 
in `defaultKeymap` which is handled by `QueryShortcuts.ts`
+                    { key: 'Mod-y', run: redoSelection },
+                    { key: 'Shift-Mod-k', run: deleteLine },
+                    {
+                        key: 'Enter',
+                        run: () => {
+                            if (this.nfEditorForm.dirty && 
this.nfEditorForm.valid) {
+                                this.okClicked();
+                                return true;
+                            }
+                            return false;
+                        }
+                    },
+                    ...closeBracketsKeymap,
+                    ...defaultKeymap,
+                    ...historyKeymap,
+                    ...foldKeymap,
+                    ...searchKeymap,

Review Comment:
   1. Since we don't support folding here, we don't need the `foldKeymap`.
   
   2. We probably don't want to support the `searchKeymap` (CMD + f). It is 
awkward if brought up in the small editor and looks really terrible in dark 
mode.
   
   <img width="1029" height="696" alt="Screenshot 2025-07-31 at 08 40 32" 
src="https://github.com/user-attachments/assets/99688265-40e3-48d5-88c0-11c9a1471dfe";
 />
   



##########
nifi-frontend/src/main/frontend/libs/shared/src/components/map-table/editors/text-editor/text-editor.component.ts:
##########
@@ -122,50 +158,67 @@ export class TextEditor {
         // needed to display the 'Set Empty String' checkbox, the action 
buttons,
         // and the resize handle. If the amount of spacing needed for 
additional UX is needed for the `.editor` is
         // changed then this value should also be updated.
-        this.editor.setSize('100%', event.height - 112);
+        this.editorStyling.width = '100%';
+        this.editorStyling.height = `${event.height - 152}px`;
     }
 
     preventDrag(event: MouseEvent): void {
         event.stopPropagation();
     }
 
-    codeMirrorLoaded(codeEditor: any): void {
-        this.editor = codeEditor.codeMirror;
-        // The `.text-editor` minimum height is set to 220px. This is the 
height of the `.editor` overlay. The
-        // height of the codemirror needs to be set in order to handle large 
amounts of text in the codemirror editor.
-        // The height of the codemirror should be the height of the `.editor` 
overlay minus the 112px of spacing
-        // needed to display the 'Set Empty String' checkbox, the action 
buttons,
-        // and the resize handle so the initial height of the codemirror when 
opening should be 108px for a 220px tall
-        // `.editor` overlay. If the initial height of that overlay changes 
then this initial height should also be
-        // updated.
-        this.editor.setSize('100%', 108);
-
-        if (!this.readonly) {
-            this.editor.focus();
-            this.editor.execCommand('selectAll');
-        }
-
+    codeMirrorLoaded(): void {
         // disabling of the input through the form isn't supported until 
codemirror
         // has loaded so we must disable again if the value is an empty string
         if (this.textEditorForm.get('setEmptyString')?.value) {
             this.textEditorForm.get('value')?.disable();
-            this.editor.setOption('readOnly', 'nocursor');
         }
     }
 
-    getOptions(): any {
-        return {
-            readOnly: this.readonly,
-            lineNumbers: true,
-            matchBrackets: true,
-            theme: 'nifi',
-            extraKeys: {
-                Enter: () => {
-                    if (this.textEditorForm.dirty && 
this.textEditorForm.valid) {
-                        this.okClicked();
+    getExtensions(): Extension[] {
+        const setup: Extension[] = [
+            lineNumbers(),
+            history(),
+            indentUnit.of('    '),
+            EditorView.lineWrapping,
+            rectangularSelection(),
+            crosshairCursor(),
+            EditorState.allowMultipleSelections.of(true),
+            indentOnInput(),
+            highlightSpecialChars(),
+            syntaxHighlighting(highlightStyle),
+            syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
+            bracketMatching(),
+            closeBrackets(),
+            highlightActiveLine(),
+            highlightSelectionMatches(),
+            [highlightActiveLineGutter(), Prec.highest(lineNumbers())],
+            foldGutter(),
+            markdown(),
+            xml(),
+            EditorView.contentAttributes.of({ 'aria-label': 'Code Editor' }),
+            keymap.of([
+                { key: 'Mod-Enter', run: () => true }, // ignore Mod-Enter in 
`defaultKeymap` which is handled by `QueryShortcuts.ts`
+                { key: 'Mod-y', run: redoSelection },
+                { key: 'Shift-Mod-k', run: deleteLine },
+                {
+                    key: 'Enter',
+                    run: () => {
+                        if (this.textEditorForm.dirty && 
this.textEditorForm.valid) {
+                            this.okClicked();
+                            return true;
+                        }
+                        return false;
                     }
-                }
-            }
-        };
+                },
+                ...closeBracketsKeymap,
+                ...defaultKeymap,
+                ...historyKeymap,
+                ...foldKeymap,
+                ...searchKeymap,

Review Comment:
   I think we can remove these as well



##########
nifi-frontend/src/main/frontend/apps/nifi/src/app/ui/common/property-table/editors/nf-editor/nf-editor.component.ts:
##########
@@ -15,21 +15,62 @@
  * limitations under the License.
  */
 
-import { Component, EventEmitter, Input, OnDestroy, Output, Renderer2, 
ViewContainerRef } from '@angular/core';
-import { PropertyItem } from '../../property-table.component';
+import { Component, EventEmitter, Input, Output, ViewContainerRef } from 
'@angular/core';
+import { PropertyItem } from '../../property-item';
 import { CdkDrag } from '@angular/cdk/drag-drop';
 import { AbstractControl, FormBuilder, FormControl, FormGroup, 
ReactiveFormsModule, Validators } from '@angular/forms';
 import { MatDialogModule } from '@angular/material/dialog';
 import { MatInputModule } from '@angular/material/input';
 import { MatButtonModule } from '@angular/material/button';
 import { MatCheckboxModule } from '@angular/material/checkbox';
-import { Resizable, Parameter, PropertyHint } from '@nifi/shared';
 import { ParameterConfig } from '../../../../../state/shared';
+import { Parameter, PropertyHintTipInput } from '@nifi/shared';
 import { A11yModule } from '@angular/cdk/a11y';
-import { CodemirrorModule } from '@ctrl/ngx-codemirror';
-import { Editor } from 'codemirror';
-import { NfEl } from './modes/nfel';
-import { NfPr } from './modes/nfpr';
+import { Extension, EditorState, Prec } from '@codemirror/state';
+import {
+    keymap,
+    highlightActiveLine,
+    lineNumbers,
+    highlightSpecialChars,
+    highlightActiveLineGutter,
+    EditorView,
+    rectangularSelection,
+    crosshairCursor
+} from '@codemirror/view';
+import {
+    acceptCompletion,
+    autocompletion,
+    closeBrackets,
+    closeBracketsKeymap,
+    completionKeymap
+} from '@codemirror/autocomplete';
+import { defaultKeymap, deleteLine, history, historyKeymap, redoSelection } 
from '@codemirror/commands';
+import {
+    defaultHighlightStyle,
+    syntaxHighlighting,
+    indentOnInput,
+    bracketMatching,
+    foldKeymap,
+    StreamLanguage,
+    indentUnit,
+    LanguageDescription
+} from '@codemirror/language';
+import { searchKeymap, highlightSelectionMatches } from '@codemirror/search';
+import {
+    Codemirror,
+    CodeMirrorConfig,
+    PropertyHint,
+    Resizable,
+    elFunctionHighlightPlugin,
+    parameterHighlightPlugin,
+    highlightStyle,
+    CodemirrorNifiLanguagePackage,
+    NfLanguageConfig,
+    NfLanguageDefinition
+} from '@nifi/shared';
+import { markdown } from '@codemirror/lang-markdown';
+import { xml } from '@codemirror/lang-xml';
+import { foldGutter } from '@codemirror/language';

Review Comment:
   unused imports can be removed. I think there are more of these mixed in with 
the changes, probably just need to run `lint` and find the rest.



##########
nifi-frontend/src/main/frontend/libs/shared/src/components/map-table/editors/text-editor/text-editor.component.ts:
##########
@@ -122,50 +158,67 @@ export class TextEditor {
         // needed to display the 'Set Empty String' checkbox, the action 
buttons,
         // and the resize handle. If the amount of spacing needed for 
additional UX is needed for the `.editor` is
         // changed then this value should also be updated.
-        this.editor.setSize('100%', event.height - 112);
+        this.editorStyling.width = '100%';
+        this.editorStyling.height = `${event.height - 152}px`;
     }
 
     preventDrag(event: MouseEvent): void {
         event.stopPropagation();
     }
 
-    codeMirrorLoaded(codeEditor: any): void {
-        this.editor = codeEditor.codeMirror;
-        // The `.text-editor` minimum height is set to 220px. This is the 
height of the `.editor` overlay. The
-        // height of the codemirror needs to be set in order to handle large 
amounts of text in the codemirror editor.
-        // The height of the codemirror should be the height of the `.editor` 
overlay minus the 112px of spacing
-        // needed to display the 'Set Empty String' checkbox, the action 
buttons,
-        // and the resize handle so the initial height of the codemirror when 
opening should be 108px for a 220px tall
-        // `.editor` overlay. If the initial height of that overlay changes 
then this initial height should also be
-        // updated.
-        this.editor.setSize('100%', 108);
-
-        if (!this.readonly) {
-            this.editor.focus();
-            this.editor.execCommand('selectAll');
-        }
-
+    codeMirrorLoaded(): void {
         // disabling of the input through the form isn't supported until 
codemirror
         // has loaded so we must disable again if the value is an empty string
         if (this.textEditorForm.get('setEmptyString')?.value) {
             this.textEditorForm.get('value')?.disable();
-            this.editor.setOption('readOnly', 'nocursor');
         }
     }
 
-    getOptions(): any {
-        return {
-            readOnly: this.readonly,
-            lineNumbers: true,
-            matchBrackets: true,
-            theme: 'nifi',
-            extraKeys: {
-                Enter: () => {
-                    if (this.textEditorForm.dirty && 
this.textEditorForm.valid) {
-                        this.okClicked();
+    getExtensions(): Extension[] {
+        const setup: Extension[] = [
+            lineNumbers(),
+            history(),
+            indentUnit.of('    '),
+            EditorView.lineWrapping,
+            rectangularSelection(),
+            crosshairCursor(),
+            EditorState.allowMultipleSelections.of(true),
+            indentOnInput(),
+            highlightSpecialChars(),
+            syntaxHighlighting(highlightStyle),
+            syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
+            bracketMatching(),
+            closeBrackets(),
+            highlightActiveLine(),
+            highlightSelectionMatches(),
+            [highlightActiveLineGutter(), Prec.highest(lineNumbers())],
+            foldGutter(),
+            markdown(),
+            xml(),

Review Comment:
   I don't think we need any of these. `<text-editor>` is only used in 
`<map-table>` currently and that is only used in 2 places. Both are for simple 
text entry, no need for folding or language support since it would be unknown 
what language the content is.
   
   Maybe I need to better understand what each of the languages added here 
does. It seems that we are telling the component that it "might" encounter 
these languages and that would enable syntax highlighting? Is that right? If 
so, maybe it does make sense to leave there here but then I'd question why json 
and yaml aren't listed as well since i'd suspect those are widely used formats 
for config type data.



##########
nifi-frontend/src/main/frontend/libs/shared/src/components/tooltips/el-function-tip/el-function-tip.component.html:
##########


Review Comment:
   Not sure where the change is coming from, but the look of the el tooltips 
isn't the same. The most noticeable difference is in the Arguments, Return and 
Subject labels. Another difference noticed, but maybe not a bad thing is the 
font difference, fixed-width before, normal now
   
   Before:
   <img width="408" height="397" alt="Screenshot 2025-07-31 at 08 53 31" 
src="https://github.com/user-attachments/assets/5c0fbf78-8911-44d4-8ce8-6b832f26caad";
 />
   
   After: 
   <img width="425" height="326" alt="Screenshot 2025-07-31 at 08 53 15" 
src="https://github.com/user-attachments/assets/fd8bd685-612d-42d4-88f7-104158094250";
 />
   
   
   _the params tooltip has similar differences_



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to