<commit_before>import {
  Component, Input, Output, ElementRef, ViewChild, OnInit, Renderer,
  EventEmitter, forwardRef, AfterViewInit, ViewEncapsulation
} from '@angular/core';
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';

import * as CodeMirror from 'codemirror';

// code extensions
import 'codemirror/mode/yaml/yaml.js';
import 'codemirror/mode/python/python.js';
import 'codemirror/mode/powershell/powershell.js';
import 'codemirror/mode/javascript/javascript.js';
import 'codemirror/mode/htmlmixed/htmlmixed.js';

// add-ons
import 'codemirror/addon/lint/lint.js';
import 'codemirror/addon/search/search.js';
import 'codemirror/addon/search/searchcursor.js';
import 'codemirror/addon/search/jump-to-line.js';
import 'codemirror/addon/dialog/dialog.js';

// themes
import * as codeMirrorCss from 'codemirror/lib/codemirror.css';
import * as lintCss from 'codemirror/addon/lint/lint.css';
import * as dialogCss from 'codemirror/addon/dialog/dialog.css';
import * as draculaCss from 'codemirror/theme/dracula.css';
import * as ngxEditorCss from './code-editor.component.scss';

const CODEMIRROR_VALUE_ACCESSOR = {
  provide: NG_VALUE_ACCESSOR,
  useExisting: forwardRef(() => CodeEditorComponent),
  multi: true
};

@Component({
  selector: 'ngx-codemirror',
  providers: [CODEMIRROR_VALUE_ACCESSOR],
  template: `
    <div visibilityObserver (visible)="onVisible()">
      <textarea #host></textarea>
      <div #content>
        <ng-content></ng-content>
      </div>
    </div>
  `,
  encapsulation: ViewEncapsulation.None,
  styles: [
    codeMirrorCss,
    lintCss,
    draculaCss,
    dialogCss,
    ngxEditorCss
  ]
})
export class CodeEditorComponent implements OnInit, AfterViewInit, ControlValueAccessor {

  @Input() config: any = {};
  @Input() theme: string = 'dracula';
  @Input() readOnly: any = false;
  @Input() mode: any;
  @Input() autofocus: boolean = false;
  @Input() lint: any;
  @Input() allowDropFileTypes: any[] = [];
  @Input() lineNumbers: any;
  @Input() gutters: any[] = [];

  set value(val: string) {
    if (val !== this._value) {
      this._value = val;
      this.onChangeCallback(val);
      this.change.emit(this._value);
    }
  }

  get value(): string {
    return this._value;
  }

  @Output() change: EventEmitter<any> = new EventEmitter();

  @ViewChild('host') host: any;
  @ViewChild('content') content;

  editor: any;
  instance: any;
  _value: string = '';

  constructor(private renderer: Renderer) { }

  ngOnInit(): void {
    this.config = Object.assign(this.config, {
      theme: this.theme,
      readOnly: this.readOnly,
      mode: this.mode,
      autofocus: this.autofocus,
      lint: this.lint,
      allowDropFileTypes: this.allowDropFileTypes,
      lineNumbers: this.lineNumbers,
      gutters: this.gutters
    });
  }

  ngAfterViewInit(): void {
    if(!this.value) {
      const elm = this.content.nativeElement;
      const code = elm.innerHTML;
      this.renderer.detachView([].slice.call(elm.childNodes));
      this.host.nativeElement.value = this.cleanCode(code);
    }

    this.instance = CodeMirror.fromTextArea(this.host.nativeElement, this.config);
    this.instance.on('change', () => {
      this.updateValue(this.instance.getValue());
    });
  }
<commit_msg>bug: remove memory leak in code editor<commit_after>import {
  Component, Input, Output, ElementRef, ViewChild, OnInit, Renderer,
  EventEmitter, forwardRef, AfterViewInit, ViewEncapsulation, OnDestroy
} from '@angular/core';
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';

import * as CodeMirror from 'codemirror';

// code extensions
import 'codemirror/mode/yaml/yaml.js';
import 'codemirror/mode/python/python.js';
import 'codemirror/mode/powershell/powershell.js';
import 'codemirror/mode/javascript/javascript.js';
import 'codemirror/mode/htmlmixed/htmlmixed.js';

// add-ons
import 'codemirror/addon/lint/lint.js';
import 'codemirror/addon/search/search.js';
import 'codemirror/addon/search/searchcursor.js';
import 'codemirror/addon/search/jump-to-line.js';
import 'codemirror/addon/dialog/dialog.js';

// themes
import * as codeMirrorCss from 'codemirror/lib/codemirror.css';
import * as lintCss from 'codemirror/addon/lint/lint.css';
import * as dialogCss from 'codemirror/addon/dialog/dialog.css';
import * as draculaCss from 'codemirror/theme/dracula.css';
import * as ngxEditorCss from './code-editor.component.scss';

const CODEMIRROR_VALUE_ACCESSOR = {
  provide: NG_VALUE_ACCESSOR,
  useExisting: forwardRef(() => CodeEditorComponent),
  multi: true
};

@Component({
  selector: 'ngx-codemirror',
  providers: [CODEMIRROR_VALUE_ACCESSOR],
  template: `
    <div visibilityObserver (visible)="onVisible()">
      <textarea #host></textarea>
      <div #content>
        <ng-content></ng-content>
      </div>
    </div>
  `,
  encapsulation: ViewEncapsulation.None,
  styles: [
    codeMirrorCss,
    lintCss,
    draculaCss,
    dialogCss,
    ngxEditorCss
  ]
})
export class CodeEditorComponent implements OnInit, AfterViewInit, OnDestroy, ControlValueAccessor {

  @Input() config: any = {};
  @Input() theme: string = 'dracula';
  @Input() readOnly: any = false;
  @Input() mode: any;
  @Input() autofocus: boolean = false;
  @Input() lint: any;
  @Input() allowDropFileTypes: any[] = [];
  @Input() lineNumbers: any;
  @Input() gutters: any[] = [];

  set value(val: string) {
    if (val !== this._value) {
      this._value = val;
      this.onChangeCallback(val);
      this.change.emit(this._value);
    }
  }

  get value(): string {
    return this._value;
  }

  @Output() change: EventEmitter<any> = new EventEmitter();

  @ViewChild('host') host: any;
  @ViewChild('content') content: any;

  editor: any;
  instance: any;
  _value: string = '';

  constructor(private renderer: Renderer) { }

  ngOnInit(): void {
    this.config = Object.assign(this.config, {
      theme: this.theme,
      readOnly: this.readOnly,
      mode: this.mode,
      autofocus: this.autofocus,
      lint: this.lint,
      allowDropFileTypes: this.allowDropFileTypes,
      lineNumbers: this.lineNumbers,
      gutters: this.gutters
    });
  }

  ngAfterViewInit(): void {
    if(!this.value) {
      const elm = this.content.nativeElement;
      const code = elm.innerHTML;
      this.renderer.detachView([].slice.call(elm.childNodes));
      this.host.nativeElement.value = this.cleanCode(code);
    }

    this.instance = CodeMirror.fromTextArea(this.host.nativeElement, this.config);
    this.instance.on('change', () => {
      this.updateValue(this.instance.getValue());
    });
  }

  ngOnDestroy(): void {
    this.instance.off('change');
  }

{'fraction_non_alphanumeric': 0.1429000300210147, 'fraction_numerical': 0.0, 'mean_word_length': 3.8564139941690962, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7481905', 'n_tokens_mistral': 2308, 'n_tokens_neox': 2252, 'n_words': 440}