Skip to content

Commit b05f191

Browse files
committed
bugs fixes, tab and arrow keys works like console
1 parent bb30655 commit b05f191

File tree

7 files changed

+122
-41
lines changed

7 files changed

+122
-41
lines changed

dist/main.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/worker.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "acode-plugin-python",
3-
"version": "1.0.5",
3+
"version": "1.0.6",
44
"description": "Acode plugin to run python code",
55
"main": "dist/main.js",
66
"repository": "https://github.com/deadlyjack/acode-plugin-python.git",

plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"id": "acode.plugin.python",
33
"name": "Python",
44
"main": "dist/main.js",
5-
"version": "1.0.5",
5+
"version": "1.0.6",
66
"readme": "README.md",
77
"icon": "icon.png",
88
"type": "pro",

src/main.js

Lines changed: 103 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class Python {
2020
$style = null;
2121
#codes = [];
2222
#niddle = 0;
23+
#inputCount = 0;
2324

2425
async init($page, cacheFile, cacheFileUrl) {
2526

@@ -67,6 +68,7 @@ class Python {
6768
className: 'print input',
6869
child: tag('textarea', {
6970
onkeydown: this.#onkeydown.bind(this),
71+
oninput: this.#oninput.bind(this),
7072
}),
7173
});
7274

@@ -93,14 +95,7 @@ class Python {
9395
}
9496

9597
async run() {
96-
const $main = this.$page.get('.main');
97-
if (!this.$page.isConnected) {
98-
this.$page.classList.remove('hide');
99-
this.$page.show();
100-
}
101-
102-
$main.innerHTML = '';
103-
98+
this.#showPage();
10499
await this.#cacheFile.writeFile('');
105100
this.#append(this.$input);
106101

@@ -116,6 +111,10 @@ class Python {
116111
await this.runCode(code);
117112
}
118113

114+
async terminal() {
115+
this.#showPage();
116+
}
117+
119118
async runCode(code) {
120119
this.#worker.postMessage({
121120
action: 'run',
@@ -168,6 +167,20 @@ class Python {
168167
this.#append($output, this.$input);
169168
}
170169

170+
#showPage() {
171+
const $main = this.$page.get('.main');
172+
if (!this.$page.isConnected) {
173+
this.$page.classList.remove('hide');
174+
this.$page.show();
175+
}
176+
$main.innerHTML = '';
177+
}
178+
179+
#clearConsole() {
180+
this.$page.get('.main').innerHTML = '';
181+
this.#append(this.$input);
182+
}
183+
171184
#append(...$el) {
172185
const $main = this.$page.get('.main');
173186
if (!$main) this.$page.append(tag('div', { className: 'main' }));
@@ -210,24 +223,12 @@ class Python {
210223
}
211224

212225
#onkeydown(e) {
213-
if (e.key === 'Enter') {
214-
e.preventDefault();
215-
const value = e.target.value;
216-
this.print(value, 'input');
217-
if (this.#isInput) {
218-
this.#isInput = false;
219-
this.#cacheFile.writeFile(value + '\0');
220-
} else {
221-
this.#codes.push(value);
222-
this.#niddle = this.#codes.length;
223-
this.runCode(value);
224-
}
225-
e.target.value = '';
226-
return;
227-
}
228-
226+
const value = e.target.value;
227+
const lines = value.split('\n');
228+
const canGoUp = this.#getCursorPosition() === 1;
229+
const canGoDown = this.#getCursorPosition() === lines.length;
229230
// if up arrow is pressed, show previous code
230-
if (e.key === 'ArrowUp') {
231+
if (canGoUp && e.key === 'ArrowUp') {
231232
e.preventDefault();
232233
if (this.#niddle > 0) {
233234
this.#niddle -= 1;
@@ -236,29 +237,100 @@ class Python {
236237
}
237238

238239
// if down arrow is pressed, show next code
239-
if (e.key === 'ArrowDown') {
240+
if (canGoDown && e.key === 'ArrowDown') {
240241
e.preventDefault();
241242
if (this.#niddle < this.#codes.length) {
242243
this.#niddle += 1;
243244
e.target.value = this.#codes[this.#niddle] || '';
244245
}
245246
}
247+
248+
// if ctrl + l is pressed, clear the input
249+
if (e.key === 'l' && e.ctrlKey) {
250+
this.#clearConsole();
251+
}
252+
253+
if (e.key === 'Tab') {
254+
e.preventDefault();
255+
e.target.value += '\t';
256+
}
246257
}
247-
}
248258

259+
#getCursorPosition() {
260+
const $textarea = this.$input.get('textarea');
261+
const {
262+
selectionStart,
263+
selectionEnd,
264+
} = $textarea;
265+
266+
if (selectionStart !== selectionEnd) return;
267+
const lines = $textarea.value;
249268

250-
console.log('Python plugin');
269+
// get the line number of the cursor
270+
return lines.slice(0, selectionStart).split('\n').length;
271+
}
272+
273+
#oninput(e) {
274+
const $el = e.target;
275+
let { value } = $el;
276+
$el.style.height = `${$el.scrollHeight}px`;
277+
// check if new line is added
278+
if (value.endsWith('\n')) {
279+
if (this.#isInput) {
280+
this.#isInput = false;
281+
value = value.slice(0, -1);
282+
this.#cacheFile.writeFile(value + `\0${this.#inputCount++}`);
283+
this.print(value, 'input');
284+
this.$input.get('textarea').value = '';
285+
return;
286+
}
287+
288+
if (!this.#isIncomplete(value)) {
289+
this.#codes.push(value.trim());
290+
this.#niddle = this.#codes.length;
291+
this.print(value, 'input');
292+
this.runCode(value);
293+
this.$input.get('textarea').value = '';
294+
}
295+
}
296+
}
297+
298+
#isIncomplete(code) {
299+
const lines = code.trim().split('\n');
300+
let lastLine = lines[lines.length - 1];
301+
302+
// if last line ends with ':', it is incomplete
303+
if (/:$/.test(lastLine)) {
304+
return true;
305+
}
306+
307+
// if last line starts with tab or soft tab, it is incomplete
308+
if (/^\W+/.test(lastLine)) {
309+
if (/\n\n$/.test(code)) {
310+
return false;
311+
}
312+
return true;
313+
}
314+
315+
return false;
316+
}
317+
}
251318

252319
if (window.acode) {
253320
const python = new Python();
254321
acode.setPluginInit('acode.plugin.python', (baseUrl, $page, { cacheFileUrl, cacheFile }) => {
255322
if (!baseUrl.endsWith('/')) baseUrl += '/';
256323
python.baseUrl = baseUrl;
257324
python.init($page, cacheFile, cacheFileUrl);
258-
console.log('Python plugin initialized');
259325
});
260326
acode.setPluginUnmount('acode.plugin.python', () => {
261327
python.destroy();
262-
console.log('Python plugin unmounted');
263-
})
328+
});
329+
// future reference
330+
if (acode.registerShortcut) {
331+
acode.registerShortcut('Python Console', python.terminal.bind(python), 'Python');
332+
}
333+
if (acode.registerMenu) {
334+
acode.registerMenu('Python Console', python.terminal.bind(python), 'Python');
335+
}
264336
}

src/style.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
outline: none;
88
resize: none;
99
flex: 1;
10+
tab-size: 4;
1011
}
1112

1213
.print{

src/worker.js

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
let inputCount = 0;
2+
13
async function loadPyodideAndPackages(baseUrl = '', packages) {
24
importScripts(`${baseUrl}/lib/pyodide.js`);
35
self.pyodide = await loadPyodide({
@@ -46,20 +48,20 @@ __builtins__.input = input
4648
self.postMessage({
4749
action: 'run',
4850
success: true,
49-
output,
51+
output: output?.toString() ?? output ?? '',
5052
});
5153
} catch (error) {
5254
self.postMessage({
5355
action: 'run',
5456
success: false,
55-
error,
57+
error: error?.message ?? error?.toString(),
5658
});
5759
}
5860
},
5961
input(data) {
6062
const { line } = data;
6163
self.line = line;
62-
},
64+
}
6365
}
6466

6567
self.onmessage = async function (e) {
@@ -77,14 +79,14 @@ self.line = '';
7779
function stdout(msg) {
7880
self.postMessage({
7981
action: 'stdout',
80-
text: msg,
82+
text: msg.message ?? msg.toString(),
8183
});
8284
}
8385

8486
function stderr(msg) {
8587
self.postMessage({
8688
action: 'stderr',
87-
text: msg,
89+
text: msg.message ?? msg.toString(),
8890
});
8991
}
9092

@@ -106,7 +108,13 @@ function read() {
106108
xhr.open('GET', self.cacheFileUrl, false);
107109
try {
108110
xhr.send();
109-
return xhr.responseText;
111+
const text = xhr.responseText;
112+
if (text.endsWith(`\0${inputCount}`)) {
113+
++inputCount;
114+
return text.slice(0, -(`${inputCount}`.length));
115+
} else {
116+
return '';
117+
}
110118
} catch (err) {
111119
throw err instanceof Error ? err : new Error(err);
112120
}

0 commit comments

Comments
 (0)