|
287 | 287 | }
|
288 | 288 | }
|
289 | 289 |
|
| 290 | + function toDigits(i, digits) { |
| 291 | + return i.toString().padStart(digits, "0"); |
| 292 | + } |
| 293 | + |
290 | 294 | async function runFile(url, showCode = true) {
|
291 | 295 | const term = window.term;
|
292 | 296 | const response = await fetch(url);
|
|
475 | 479 | let unlock = await lock();
|
476 | 480 | term.pause();
|
477 | 481 | // multiline should be split (useful when pasting)
|
478 |
| - for (const c of command.split("\n")) { |
| 482 | + let counter = 0; |
| 483 | + const lines = command.split("\n"); |
| 484 | + for (const c of lines) { |
| 485 | + counter++; |
479 | 486 | const escaped = c.replaceAll(/\u00a0/g, " ");
|
480 | 487 | let fut = pyconsole.push(escaped);
|
481 | 488 | term.set_prompt(fut.syntax_check === "incomplete" ? ps2 : ps1);
|
|
529 | 536 | } catch (e) {
|
530 | 537 | if (e.constructor.name === "PythonError") {
|
531 | 538 | const message = fut.formatted_error || e.message;
|
532 |
| - term.error(message.trimEnd()); |
| 539 | + let msg = ""; |
| 540 | + if (lines.length > 1) { |
| 541 | + // print the error position in multiline mode |
| 542 | + const limit = 3; |
| 543 | + const maxDigits = (counter + limit).toString().length; |
| 544 | + msg += `Error occred at line ${counter}:\n`; |
| 545 | + msg += "----------------------------------------\n" |
| 546 | + let i = 0; |
| 547 | + for (const line of lines) { |
| 548 | + i++; |
| 549 | + if (i === counter) { |
| 550 | + msg += toDigits(i, maxDigits) + ": " + line + " <-- Error here!" + "\n"; |
| 551 | + } else if ((i >= counter - limit) && (i <= counter + limit)) { |
| 552 | + msg += toDigits(i, maxDigits) + ": " + line + "\n"; |
| 553 | + } |
| 554 | + } |
| 555 | + msg += "----------------------------------------\n" |
| 556 | + } |
| 557 | + msg += message.trimEnd(); |
| 558 | + term.error(msg); |
533 | 559 | break;
|
534 | 560 | } else {
|
535 | 561 | throw e;
|
|
0 commit comments