1
1
import './style.css' ;
2
- import 'xterm/lib/xterm.css' ;
3
- import CodeMirror from 'codemirror' ;
4
- import 'codemirror/mode/python/python' ;
5
- import 'codemirror/addon/comment/comment' ;
6
- import 'codemirror/lib/codemirror.css' ;
7
- import { Terminal } from 'xterm' ;
8
- import LocalEchoController from 'local-echo' ;
2
+ import '@xterm/xterm/css/xterm.css' ;
3
+ import { EditorView , basicSetup } from 'codemirror' ;
4
+ import { keymap } from '@codemirror/view' ;
5
+ import { indentUnit } from '@codemirror/language' ;
6
+ import { indentWithTab } from '@codemirror/commands' ;
7
+ import { python } from '@codemirror/lang-python' ;
8
+ import { Terminal } from '@xterm/xterm' ;
9
+ import { FitAddon } from '@xterm/addon-fit' ;
10
+ import { Readline } from 'xterm-readline' ;
9
11
10
12
let rp ;
11
13
@@ -22,23 +24,24 @@ import('rustpython')
22
24
document . getElementById ( 'error' ) . textContent = e ;
23
25
} ) ;
24
26
25
- const editor = CodeMirror . fromTextArea ( document . getElementById ( 'code' ) , {
26
- extraKeys : {
27
- 'Ctrl-Enter' : runCodeFromTextarea ,
28
- 'Cmd-Enter' : runCodeFromTextarea ,
29
- 'Shift-Tab' : 'indentLess' ,
30
- 'Ctrl-/' : 'toggleComment' ,
31
- 'Cmd-/' : 'toggleComment' ,
32
- Tab : ( editor ) => {
33
- var spaces = Array ( editor . getOption ( 'indentUnit' ) + 1 ) . join ( ' ' ) ;
34
- editor . replaceSelection ( spaces ) ;
35
- } ,
36
- } ,
37
- lineNumbers : true ,
38
- mode : 'text/x-python' ,
39
- indentUnit : 4 ,
40
- autofocus : true ,
27
+ const fixedHeightEditor = EditorView . theme ( {
28
+ '&' : { height : '100%' } ,
29
+ '.cm-scroller' : { overflow : 'auto' } ,
41
30
} ) ;
31
+ const editor = new EditorView ( {
32
+ parent : document . getElementById ( 'code-wrapper' ) ,
33
+ extensions : [
34
+ basicSetup ,
35
+ python ( ) ,
36
+ keymap . of (
37
+ { key : 'Ctrl-Enter' , mac : 'Cmd-Enter' , run : runCodeFromTextarea } ,
38
+ indentWithTab ,
39
+ ) ,
40
+ indentUnit . of ( ' ' ) ,
41
+ fixedHeightEditor ,
42
+ ] ,
43
+ } ) ;
44
+ editor . focus ( ) ;
42
45
43
46
const consoleElement = document . getElementById ( 'console' ) ;
44
47
const errorElement = document . getElementById ( 'error' ) ;
@@ -48,7 +51,7 @@ function runCodeFromTextarea() {
48
51
consoleElement . value = '' ;
49
52
errorElement . textContent = '' ;
50
53
51
- const code = editor . getValue ( ) ;
54
+ const code = editor . state . doc . toString ( ) ;
52
55
try {
53
56
rp . pyExec ( code , {
54
57
stdout : ( output ) => {
@@ -78,18 +81,25 @@ function updateSnippet() {
78
81
// the require here creates a webpack context; it's fine to use it
79
82
// dynamically.
80
83
// https://webpack.js.org/guides/dependency-management/
81
- const { default : snippet } = require (
82
- `raw-loader!../snippets/${ selected } .py` ,
83
- ) ;
84
+ const snippet = require ( `../snippets/${ selected } .py?raw` ) ;
84
85
85
- editor . setValue ( snippet ) ;
86
- runCodeFromTextarea ( ) ;
86
+ editor . dispatch ( {
87
+ changes : { from : 0 , to : editor . state . doc . length , insert : snippet } ,
88
+ } ) ;
87
89
}
90
+ function updateSnippetAndRun ( ) {
91
+ updateSnippet ( ) ;
92
+ requestAnimationFrame ( runCodeFromTextarea ) ;
93
+ }
94
+ updateSnippet ( ) ;
88
95
89
96
const term = new Terminal ( ) ;
97
+ const readline = new Readline ( ) ;
98
+ const fitAddon = new FitAddon ( ) ;
99
+ term . loadAddon ( readline ) ;
100
+ term . loadAddon ( fitAddon ) ;
90
101
term . open ( document . getElementById ( 'terminal' ) ) ;
91
-
92
- const localEcho = new LocalEchoController ( term ) ;
102
+ fitAddon . fit ( ) ;
93
103
94
104
let terminalVM ;
95
105
@@ -107,48 +117,41 @@ finally:
107
117
}
108
118
109
119
async function readPrompts ( ) {
110
- let continuing = false ;
120
+ let continuing = '' ;
111
121
112
122
while ( true ) {
113
- const ps1 = getPrompt ( 'ps1' ) ;
114
- const ps2 = getPrompt ( 'ps2' ) ;
115
- let input ;
123
+ let input = await readline . read ( getPrompt ( continuing ? 'ps2' : 'ps1' ) ) ;
124
+ if ( input . endsWith ( '\n' ) ) input = input . slice ( 0 , - 1 ) ;
116
125
if ( continuing ) {
117
- const prom = localEcho . read ( ps2 , ps2 ) ;
118
- localEcho . _activePrompt . prompt = ps1 ;
119
- localEcho . _input = localEcho . history . entries . pop ( ) + '\n' ;
120
- localEcho . _cursor = localEcho . _input . length ;
121
- localEcho . _active = true ;
122
- input = await prom ;
123
- if ( ! input . endsWith ( '\n' ) ) continue ;
124
- } else {
125
- input = await localEcho . read ( ps1 , ps2 ) ;
126
+ input = continuing += '\n' + input ;
127
+ if ( ! continuing . endsWith ( '\n' ) ) continue ;
126
128
}
127
129
try {
130
+ console . log ( [ input ] ) ;
128
131
terminalVM . execSingle ( input ) ;
129
132
} catch ( err ) {
130
133
if ( err . canContinue ) {
131
- continuing = true ;
134
+ continuing = input ;
132
135
continue ;
133
136
} else if ( err instanceof WebAssembly . RuntimeError ) {
134
137
err = window . __RUSTPYTHON_ERROR || err ;
135
138
}
136
- localEcho . println ( err ) ;
139
+ readline . print ( '' + err ) ;
137
140
}
138
- continuing = false ;
141
+ continuing = '' ;
139
142
}
140
143
}
141
144
142
145
function onReady ( ) {
143
- snippets . addEventListener ( 'change' , updateSnippet ) ;
146
+ snippets . addEventListener ( 'change' , updateSnippetAndRun ) ;
144
147
document
145
148
. getElementById ( 'run-btn' )
146
149
. addEventListener ( 'click' , runCodeFromTextarea ) ;
147
150
// Run once for demo
148
151
runCodeFromTextarea ( ) ;
149
152
150
153
terminalVM = rp . vmStore . init ( 'term_vm' ) ;
151
- terminalVM . setStdout ( ( data ) => localEcho . print ( data ) ) ;
154
+ terminalVM . setStdout ( ( data ) => readline . print ( data ) ) ;
152
155
readPrompts ( ) . catch ( ( err ) => console . error ( err ) ) ;
153
156
154
157
// so that the test knows that we're ready
0 commit comments