<commit_before>// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.

import {
  ILabShell,
  ILayoutRestorer,
  JupyterFrontEnd,
  JupyterFrontEndPlugin
} from '@jupyterlab/application';

import {
  IClientSession,
  ICommandPalette,
  Toolbar,
  ToolbarButton
} from '@jupyterlab/apputils';

import { IEditorServices } from '@jupyterlab/codeeditor';

import { ConsolePanel, IConsoleTracker } from '@jupyterlab/console';

import { IStateDB } from '@jupyterlab/coreutils';

import { DocumentWidget } from '@jupyterlab/docregistry';

import { FileEditor, IEditorTracker } from '@jupyterlab/fileeditor';

import { INotebookTracker, NotebookPanel } from '@jupyterlab/notebook';

import { Session } from '@jupyterlab/services';

import { Debugger } from './debugger';

import { ConsoleHandler } from './handlers/console';

import { FileHandler } from './handlers/file';

import { NotebookHandler } from './handlers/notebook';

import { TrackerHandler } from './handlers/tracker';

import { DebugService } from './service';

import { DebugSession } from './session';

import { IDebugger } from './tokens';

/**
 * The command IDs used by the debugger plugin.
 */
export namespace CommandIDs {
  export const create = 'debugger:create';

  export const start = 'debugger:start';

  export const stop = 'debugger:stop';

  export const debugContinue = 'debugger:continue';

  export const terminate = 'debugger:terminate';

  export const next = 'debugger:next';

  export const stepIn = 'debugger:stepIn';

  export const stepOut = 'debugger:stepOut';

  export const debugConsole = 'debugger:debug-console';

  export const close = 'debugger:close';
}

async function setDebugSession(
  app: JupyterFrontEnd,
  debug: IDebugger,
  client: IClientSession | Session.ISession
) {
  if (!debug.session) {
    debug.session = new DebugSession({ client: client });
  } else {
    debug.session.client = client;
  }
  app.commands.notifyCommandChanged();
}

class DebuggerHandler<
  H extends ConsoleHandler | NotebookHandler | FileHandler
> {
  /**
   * Instantiate a new DebuggerHandler.
   * @param builder The debug handler builder.
   */
  constructor(builder: new (option: any) => H) {
    this._builder = builder;
  }

  /**
   * Update a debug handler for the given widget.
   * @param debug The debug service.
   * @param widget The widget to update.
   * @param content The content widget to handle.
   */
  async update<
    W extends ConsolePanel | NotebookPanel | DocumentWidget,
    C extends ConsolePanel | NotebookPanel | FileEditor
  >(debug: IDebugger, widget: W, content: C): Promise<void> {
    const debuggingEnabled = await debug.requestDebuggingEnabled();
    if (!debug.model || !debuggingEnabled) {
      return;
    }
    this._addToolbarButton(debug, widget, content);

    content.disposed.connect(() => {
      const handler = this._handlers[widget.id];
      if (!handler) {
        return;
      }
      handler.dispose();
      delete this._handlers[widget.id];
    });

    debug.model.disposed.connect(async () => {
      const handlerIds = Object.keys(this._handlers);
      if (handlerIds.length === 0) {
        return;
      }
      await debug.stop();
      debug.session.dispose();
      debug.session = null;
      handlerIds.forEach(id => {
        this._handlers[id].dispose();
      });
      this._handlers = {};
    });

    // TODO: stop the debugger if started and the widget gets the focus
  }

  /**
   * Add a button to the widget's toolbar to enable and disable debugging.
   * @param debug The debug service.
   * @param widget The widget to add the debug toolbar button to.
   */
  private _addToolbarButton(
    debug: IDebugger,
    widget: NotebookPanel | ConsolePanel | DocumentWidget,
    content: NotebookPanel | ConsolePanel | FileEditor
  ) {
    const isEnabled = () => {
      const currentPath = debug.session.client.path;
      return debug.session.debuggedClients.has(currentPath);
    };

    const toggleAttribute = () => {
      if (!isEnabled()) {
        widget.node.removeAttribute('data-jp-debugger');
        return;
      }
      widget.node.setAttribute('data-jp-debugger', 'true');
    };

    const createHandler = async () => {
      if (this._handlers[widget.id] || !isEnabled()) {
        return;
      }
      await debug.restoreState(true);
      this._handlers[widget.id] = new this._builder({<commit_msg>Restore state on current widget changed<commit_after>// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.

import {
  ILabShell,
  ILayoutRestorer,
  JupyterFrontEnd,
  JupyterFrontEndPlugin
} from '@jupyterlab/application';

import {
  IClientSession,
  ICommandPalette,
  Toolbar,
  ToolbarButton
} from '@jupyterlab/apputils';

import { IEditorServices } from '@jupyterlab/codeeditor';

import { ConsolePanel, IConsoleTracker } from '@jupyterlab/console';

import { IStateDB } from '@jupyterlab/coreutils';

import { DocumentWidget } from '@jupyterlab/docregistry';

import { FileEditor, IEditorTracker } from '@jupyterlab/fileeditor';

import { INotebookTracker, NotebookPanel } from '@jupyterlab/notebook';

import { Session } from '@jupyterlab/services';

import { Debugger } from './debugger';

import { ConsoleHandler } from './handlers/console';

import { FileHandler } from './handlers/file';

import { NotebookHandler } from './handlers/notebook';

import { TrackerHandler } from './handlers/tracker';

import { DebugService } from './service';

import { DebugSession } from './session';

import { IDebugger } from './tokens';

/**
 * The command IDs used by the debugger plugin.
 */
export namespace CommandIDs {
  export const create = 'debugger:create';

  export const start = 'debugger:start';

  export const stop = 'debugger:stop';

  export const debugContinue = 'debugger:continue';

  export const terminate = 'debugger:terminate';

  export const next = 'debugger:next';

  export const stepIn = 'debugger:stepIn';

  export const stepOut = 'debugger:stepOut';

  export const debugConsole = 'debugger:debug-console';

  export const close = 'debugger:close';
}

async function setDebugSession(
  app: JupyterFrontEnd,
  debug: IDebugger,
  client: IClientSession | Session.ISession
) {
  if (!debug.session) {
    debug.session = new DebugSession({ client: client });
  } else {
    debug.session.client = client;
  }
  app.commands.notifyCommandChanged();
}

class DebuggerHandler<
  H extends ConsoleHandler | NotebookHandler | FileHandler
> {
  /**
   * Instantiate a new DebuggerHandler.
   * @param builder The debug handler builder.
   */
  constructor(builder: new (option: any) => H) {
    this._builder = builder;
  }

  /**
   * Update a debug handler for the given widget.
   * @param debug The debug service.
   * @param widget The widget to update.
   * @param content The content widget to handle.
   */
  async update<
    W extends ConsolePanel | NotebookPanel | DocumentWidget,
    C extends ConsolePanel | NotebookPanel | FileEditor
  >(debug: IDebugger, widget: W, content: C): Promise<void> {
    const debuggingEnabled = await debug.requestDebuggingEnabled();
    if (!debug.model || !debuggingEnabled) {
      return;
    }
    this._addToolbarButton(debug, widget, content);

    content.disposed.connect(() => {
      const handler = this._handlers[widget.id];
      if (!handler) {
        return;
      }
      handler.dispose();
      delete this._handlers[widget.id];
    });

    debug.model.disposed.connect(async () => {
      const handlerIds = Object.keys(this._handlers);
      if (handlerIds.length === 0) {
        return;
      }
      await debug.stop();
      debug.session.dispose();
      debug.session = null;
      handlerIds.forEach(id => {
        this._handlers[id].dispose();
      });
      this._handlers = {};
    });

    await debug.restoreState(false);
  }

  /**
   * Add a button to the widget's toolbar to enable and disable debugging.
   * @param debug The debug service.
   * @param widget The widget to add the debug toolbar button to.
   */
  private _addToolbarButton(
    debug: IDebugger,
    widget: NotebookPanel | ConsolePanel | DocumentWidget,
    content: NotebookPanel | ConsolePanel | FileEditor
  ) {
    const isEnabled = () => {
      const currentPath = debug.session.client.path;
      return debug.session.debuggedClients.has(currentPath);
    };

    const toggleAttribute = () => {
      if (!isEnabled()) {
        widget.node.removeAttribute('data-jp-debugger');
        return;
      }
      widget.node.setAttribute('data-jp-debugger', 'true');
    };

    const createHandler = async () => {
      if (this._handlers[widget.id] || !isEnabled()) {
        return;
      }
      await debug.restoreState(true);
      this._handlers[widget.id] = new this._builder({
{'fraction_non_alphanumeric': 0.12018089315997739, 'fraction_numerical': 0.00022611644997173544, 'mean_word_length': 3.3320274240940253, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2915091', 'n_tokens_mistral': 2660, 'n_tokens_neox': 2618, 'n_words': 692}