index.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. const MINIMUM_COLS = 2
  2. const MINIMUM_ROWS = 1
  3. class FitAddon {
  4. constructor() {}
  5. activate(terminal) {
  6. this._terminal = terminal
  7. }
  8. dispose() {}
  9. fit() {
  10. const dims = this.proposeDimensions()
  11. if (!dims || !this._terminal || isNaN(dims.cols) || isNaN(dims.rows)) {
  12. return
  13. }
  14. // TODO: Remove reliance on private API
  15. const core = this._terminal._core
  16. // Force a full render
  17. if (
  18. this._terminal.rows !== dims.rows ||
  19. this._terminal.cols !== dims.cols
  20. ) {
  21. core._renderService.clear()
  22. this._terminal.resize(dims.cols, dims.rows)
  23. }
  24. }
  25. proposeDimensions() {
  26. if (!this._terminal) {
  27. return undefined
  28. }
  29. if (!this._terminal.element || !this._terminal.element.parentElement) {
  30. return undefined
  31. }
  32. // TODO: Remove reliance on private API
  33. const core = this._terminal._core
  34. const dims = core._renderService.dimensions
  35. if (dims.actualCellWidth === 0 || dims.actualCellHeight === 0) {
  36. return undefined
  37. }
  38. const scrollbarWidth =
  39. this._terminal.options.scrollback === 0 ? 0 : core.viewport.scrollBarWidth
  40. const parentElementStyle = window.getComputedStyle(
  41. this._terminal.element.parentElement
  42. )
  43. const parentElementHeight = parseInt(
  44. parentElementStyle.getPropertyValue("height")
  45. )
  46. const parentElementWidth = Math.max(
  47. 0,
  48. parseInt(parentElementStyle.getPropertyValue("width"))
  49. )
  50. const elementStyle = window.getComputedStyle(this._terminal.element)
  51. const elementPadding = {
  52. top: parseInt(elementStyle.getPropertyValue("padding-top")),
  53. bottom: parseInt(elementStyle.getPropertyValue("padding-bottom")),
  54. right: parseInt(elementStyle.getPropertyValue("padding-right")),
  55. left: parseInt(elementStyle.getPropertyValue("padding-left"))
  56. }
  57. const elementPaddingVer = elementPadding.top + elementPadding.bottom
  58. const elementPaddingHor = elementPadding.right + elementPadding.left
  59. const availableHeight = parentElementHeight - elementPaddingVer
  60. const availableWidth =
  61. parentElementWidth - elementPaddingHor - scrollbarWidth
  62. const geometry = {
  63. cols: Math.max(
  64. MINIMUM_COLS,
  65. Math.floor(availableWidth / dims.actualCellWidth)
  66. ),
  67. rows: Math.max(
  68. MINIMUM_ROWS,
  69. Math.floor(availableHeight / dims.actualCellHeight)
  70. )
  71. }
  72. return geometry
  73. }
  74. }
  75. const term = new Terminal(
  76. {
  77. cursorBlink: true,
  78. fontSize: 16,
  79. theme: {
  80. background: '#282C34',
  81. foreground: '#ffffff',
  82. cursor: '#ffffff',
  83. cursorAccent: '#282C34',
  84. selection: '#41454E',
  85. },
  86. }
  87. );
  88. var command = "";
  89. var need_more_lines = false;
  90. var stopped = false;
  91. var repl = 0;
  92. var Module = {
  93. 'print': function(text) {
  94. term.write(text + "\r\n");
  95. },
  96. 'printErr': function(text) {
  97. term.write(text + "\r\n");
  98. },
  99. 'onRuntimeInitialized': function(text) {
  100. var vm = Module.ccall('pkpy_new_vm', 'number', ['boolean'], [true]);
  101. repl = Module.ccall('pkpy_new_repl', 'number', ['number'], [vm]);
  102. term.write(need_more_lines ? "... " : ">>> ");
  103. },
  104. 'onAbort': function(text) {
  105. stopped = true;
  106. },
  107. };
  108. function term_init() {
  109. term.open(document.getElementById('terminal'));
  110. const addon = new FitAddon();
  111. term.loadAddon(addon);
  112. addon.fit();
  113. // refit when window is resized
  114. window.addEventListener('resize', () => {
  115. addon.fit();
  116. });
  117. term.onData(e => {
  118. if (stopped) return;
  119. switch (e) {
  120. case '\r': // Enter
  121. term.write("\r\n");
  122. need_more_lines = Module.ccall('pkpy_repl_input', 'bool', ['number', 'string'], [repl, command]);
  123. command = '';
  124. term.write(need_more_lines ? "... " : ">>> ");
  125. break;
  126. case '\u007F': // Backspace (DEL)
  127. // Do not delete the prompt
  128. if (term._core.buffer.x > 4) { // '>>> ' or '... '
  129. term.write('\b \b');
  130. if (command.length > 0) {
  131. command = command.substr(0, command.length - 1);
  132. }
  133. }
  134. break;
  135. default: // Print all other characters for demo
  136. if (e >= String.fromCharCode(0x20) && e <= String.fromCharCode(0x7E) || e >= '\u00a0') {
  137. command += e;
  138. term.write(e);
  139. }
  140. }
  141. });
  142. }