1

I'm building my own application that has a JavaScript backend for user scripting, and am implementing something similar to Chrome's JavaScript console.

One thing that's puzzling me is the logic that Chrome uses to decide when the return key triggers the command to be executed, and when it auto continues to a new line.

For example if you type

function blah() { <return>

then it continues on to the next line to allow you to continue typing the function, whereas

function blah() {] <return>

immediately gives a parse error (so it's not as simple as just keeping count of open bracket pairs)

Does anyone have any hits (or is anyone familiar enough with the Chromium source who's able to point me to that particular logic in their codebase)

benjymous
  • 2,102
  • 1
  • 14
  • 21
  • 1
    `so it's not as simple as just keeping count of open bracket pairs` really? If an opened `{` was closed with an `]` thats definetly an error – Jonas Wilms Jul 29 '18 at 14:04
  • If I remember it, it requires Shift + Enter to move to new line, just pressing Enter results in immediate parsing – Dipen Shah Jul 29 '18 at 14:10
  • You can inspect the [source code](https://cs.chromium.org/chromium/src/third_party/blink/renderer/devtools/front_end/console/ConsolePrompt.js?q=_enterKeyPressed&l=223). You can also debug the devtools itself by opening [devtools-on-devtools](https://stackoverflow.com/a/27661701). – wOxxOm Jul 29 '18 at 14:28

1 Answers1

2

Here's the source that decides what to do when Enter is pressed (thanks, wOxxOm):

  async _enterKeyPressed(event) {
    if (event.altKey || event.ctrlKey || event.shiftKey)
      return;

    event.consume(true);

    this.clearAutocomplete();

    const str = this.text();
    if (!str.length)
      return;

    if (!this._isCaretAtEndOfPrompt()) {
      await this._appendCommand(str, true);
      return;
    }

    if (await ObjectUI.JavaScriptAutocomplete.isExpressionComplete(str))
      await this._appendCommand(str, true);
    else
      this._editor.newlineAndIndent();
    this._enterProcessedForTest();
  }

And here's the source that determines if an expression is complete:

  static async isExpressionComplete(expression) {
    const currentExecutionContext = UI.context.flavor(SDK.ExecutionContext);
    if (!currentExecutionContext)
      return true;
    const result =
        await currentExecutionContext.runtimeModel.compileScript(expression, '', false, currentExecutionContext.id);
    if (!result.exceptionDetails)
      return true;
    const description = result.exceptionDetails.exception.description;
    return !description.startsWith('SyntaxError: Unexpected end of input') &&
        !description.startsWith('SyntaxError: Unterminated template literal');
  }

If my interpretation is correct, it looks like DevTools just compiles the expression and uses that result to determine if the expression is complete. If there's exceptions or errors, it's not complete.

Kayce Basques
  • 23,849
  • 11
  • 86
  • 120
  • Brilliant, thanks! I had a feeling it was just brute force compiling each time you pressed enter, but was hoping there was something smarter going on :) – benjymous Jul 29 '18 at 20:08